[erlang-questions] gen_server & wait/notify
Dmitry Kolesnikov
dmkolesnikov@REDACTED
Fri Sep 29 10:37:23 CEST 2017
+1 to Craig
The usage of blocking receive within gen_server is possible but then the value of async call is questionable in your design. You either make it fully async with state-machine like approach or make it sync.
Best Regards,
Dmitry
> On 29 Sep 2017, at 10.40, zxq9 <zxq9@REDACTED> wrote:
>
> On 2017年09月29日 金曜日 16:23:42 zxq9 wrote:
>> On 2017年09月28日 木曜日 17:58:08 Chris Waymire wrote:
>>> handle_call({request, Data#data{uid=UID}}, _From, State) ->
>>> make_asycnc_req(Data),
>>> receive
>>> {UID, Response} -> {reply, Response, State}
>>> end.
>>>
>>> handle_info({response, Response#response{uid=UID}}, State) ->
>>> self() ! {UID, Response},
>>> {noreply, State}.
>>
>>
>> Your naked `receive` will work just fine. The flow of the process has never
>> returned to the gen_server module yet to await another message to dispatch,
>> so when you write a naked `receive` in some handling code that is exactly
>> where the process will block, and you can receive any arbitrary thing you
>> want there. Just be careful not to match on any system or gen_server message
>> types and you'll get the behavior you expect (though your mailbox may be
>> filling up with other stuff in the meantime).
>
> One note of caution is that you might actually be fighting against the
> natural order of things. Consider carefully whether you need this and what
> it is achieving for you. You may really be better off with casts. See if
> there is a way for you to design the system to be entirely async, and if
> not, why not. What state is being async going to threaten? Is it an
> ordering issue? Are you relaying a message and waiting for a response
> that will be returned? If so, why is the originating process not just
> receiving the response directly? (Do you really need a middle-man?)
>
> Another way to achieve this without blocking is to use references to
> tag messages and keep a digest of them. That prevents your gen_server
> from becoming unresponsive to system messages or blocking indefinitely
> in the event the sender of the message you are waiting on crashes.
>
> This is actually what the `From` argument to handle_call/3 is for:
>
> handle_call({request, Data = data{uid = UID}},
> {Sender, Tag},
> State = #s{queue = Q}) ->
> ok = make_async_request(Data, Tag),
> {noreply, State#s{queue = [{{Tag, UID, Sender} | Queue]}};
> % ...
>
> handle_cast({response, {Tag, UID}, Message}, State = #s{queue = Queue}) ->
> case lists:keyfind(Tag, 1, Queue) of
> Ticket = {Tag, UID, Sender} ->
> NewState = State#s{queue = lists:delete(Ticket, Queue)},
> {reply, Message, NewState};
> false ->
> LogString = "Received bad message: ~tp",
> ok = log(warning, LogString, [{{Tag, UID}, Message}]),
> {noreply, State}
> end;
> % ...
>
> There may be any number of ways you might want to phrase that or structure
> it, but basically that's how you can safely stow such a pending response
> value and sender, and get the response back out to them without any weird
> blockages or unresponsiveness.
>
> -Craig
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
> http://erlang.org/mailman/listinfo/erlang-questions <http://erlang.org/mailman/listinfo/erlang-questions>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20170929/271b3826/attachment.htm>
More information about the erlang-questions
mailing list