OK, I can give you an example and you can play with it
But just from learn, we will never write these code in produce!!!
maybe your demand is simple, but there is more thing we have to do in produce(supervisor, database, complex logic.etc)
So, again, just from learn!!!
play with test:run().
-module(test).
-compile([export_all, nowarn_export_all]).
run() ->
%% using dets for example
file:delete("example.dets"),
%% this step should do in other place
%% like `xxx_sup` when app start
case dets:info(example, owner) of
undefined ->
dets:open_file(example, [{file, "example.dets"}]);
_ ->
skip
end,
spawn(fun() -> init() end),
%% wait for start
timer:sleep(100),
Client = self(),
%% normal operation
example_server ! {allocate, Client, aaa, 1},
example_server ! {allocate, Client, bbb, 1},
example_server ! {allocate, Client, aaa, 1},
timer:sleep(1000),
example_server ! {release, Client, aaa, 1},
example_server ! {release, Client, aaa, 1},
%% ensure receive all msg
timer:sleep(100),
io:format("~p~n", [receive_server_msg([])]),
%% allocate then server be killed
example_server ! {allocate, Client, aaa, 1},
%% ensure receive all msg
timer:sleep(100),
exit(whereis(example_server), kill),
%% restart by somewhere(your sup)
spawn(fun() -> init() end),
%% wait for start
timer:sleep(100),
example_server ! {allocate, Client, bbb, 1},
example_server ! {allocate, Client, aaa, 1},
timer:sleep(1000),
example_server ! {release, Client, aaa, 1},
example_server ! {release, Client, aaa, 1},
%% ensure receive all msg
timer:sleep(100),
io:format("~p~n", [receive_server_msg([])]),
example_server ! {stop},
dets:close(example).
receive_server_msg(List) ->
receive
Reply ->
receive_server_msg([Reply|List])
after 0 ->
lists:reverse(List)
end.
init() ->
erlang:register(example_server, self()),
State = other_data_you_need,
manager(State).
manager(State) ->
receive
{stop} -> ok;
{allocate, Requestor, Name, Frequency} ->
%% check client request and server state
%% of course you should do more and better, this is just an example
case check_allocate_request_and_modify_state(Name, Frequency, State) of
{ok, State1} ->
%% tell client you can use it
Requestor ! {grant, Frequency},
manager(State1);
{error, Reason} ->
%% tell client you can't use it and why
Requestor ! {error, Reason},
manager(State)
end;
{release, Requestor, Name, Frequency} ->
%% same logic as before
case check_release_request_and_modify_state(Name, Frequency, State) of
{ok, Cost, State1} ->
%% tell client bill
Requestor ! {bill, Cost},
manager(State1);
{error, Reason} ->
Requestor ! {error, Reason},
manager(State)
end;
UnknownMsg ->
logger:error("unknown message: ~p", [UnknownMsg]),
manager(State)
end.
check_allocate_request_and_modify_state(Name, Frequency, State) ->
%% Is valid Frequency
case lists:member(Frequency, [1,2,3,4,5]) of
true ->
%% Is someone using
case dets:lookup(example, Frequency) of
[] ->
dets:insert(example, {Frequency, Name, erlang:system_time(second)}),
{ok, State};
[{_, Name, _}] ->
{error, using};
_ ->
{error, other_using}
end;
_ ->
{error, bad_request}
end.
check_release_request_and_modify_state(Name, Frequency, State) ->
case dets:lookup(example, Frequency) of
[{_, Name, StartTime}] ->
dets:delete(example, Frequency),
Cost = (erlang:system_time(second) - StartTime),% * Price,
{ok, Cost, State};
_ ->
{error, not_using}
end.