I’m always looking for that links

gen_server behaviour is the easiest of all behaviours out there, and the source below is an equivalent of the code I showed before.

-module(gs). -behaviour(gen_server). %% API -export([start_link/1]). -export([inc/2, dec/2, get/1, set/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). start_link(InitialCounter) -> gen_server:start_link(?MODULE, [InitialCounter], []). inc(Pid, Val)-> ok = gen_server:cast(Pid, {inc, Val}). dec(Pid, Val)-> ok = gen_server:cast(Pid, {dec, Val}). get(Pid)-> {counter, State} = gen_server:call(Pid, get), State. set(Pid, NewState)-> ok = gen_server:cast(Pid, {set, NewState}). %%callbacks------------------------------------------- init([InitialCounter]) -> %do needed computaton and start looping State = InitialCounter, {ok, State}. handle_call(get, _From, State) -> Reply = {counter, State}, {reply, Reply, State}. handle_cast({inc, Val}, State) -> {noreply, State+Val}; handle_cast({dec, Val}, State) -> {noreply, State-Val}; handle_cast({set, NewState}, _State) -> {noreply, NewState}. %% Description: Handling all non call/cast messages handle_info(_Info, State) ->{noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) ->{ok, State}.

ok, code grew again :) but we gained clear and easy to maintain server that is just counting, and all looping is well hidden from us. What I don’t understand is why cast don’t provide From value, or maybe I miss something..

Manual is more or less clear but for long time I had no idea what are reply/2 and enter_loop/3 for and how to use them.

reply(Client, Reply) -> Result

Types:

Client – see below

Reply = term()

Result = term() This function can be used by a gen_server to explicitly send a reply to a client that called call/2,3 or multi_call/2,3,4, when the reply cannot be defined in the return value of Module:handle_call/3.

Client must be the From argument provided to the callback function. Reply is an arbitrary term, which will be given back to the client as the return value of call/2,3 or multi_call/2,3,4.

The return value Result is not further defined, and should always be ignored.

So

when the reply cannot be defined in the return value of Module:handle_call/3.

really means that, while caller (C) is still waiting for a replay (and he always will if no timeout is specified), we (service A) could save From value and call asynchronously other service (B) and return from handle_call/3 with no replay. Now while waiting for replay from the other service (B) we can process next call (or cast) and as soon as the service (B) return then we can send the answer back to caller.

async_get(Pid, Val) -> {async_replay, Result} = gen_server:call(Pid, {async_call, Val}), Result. async_replay(Pid, FromVal, Result) -> ok = gen_server:cast(Pid, {async_replay, FromVal, Result}). handle_call({async_call, Val}, From, State) -> %save From in local session %ets:insert(State#state.tab_name, {SessionID, From}), %serviceB:process(SessionID, self(), Val), %OR simply send From to other service serviceB:process(SessionID, self(), From, Val), {noreply, State}; ... handle_cast({async_replay, FromVal, Result}, State) -> %[{SessionID, From}] = ets:lookup(State#state.tab_name, FromVal), %ets:delete(State#state.tab_name, FromId), %OR simply send back the result From = FromId, gen_server:reply(From, {async_replay, Result}), {noreply, State}; ...

I still have no idea how to use enter_loop fun :) maybe some day :)