[erlang-questions] gen_server & wait/notify

Chris Waymire chris@REDACTED
Sun Oct 1 19:22:34 CEST 2017


I'll try to provide some context around what I am doing. Basically I am
writing a client for a custom MQTT network that in addition to the basic
MQTT functionality also provides a request/response system. So the idea
here is that when a user of the app executes the "request" function a uuid
will be attached to their message payload and published onto the network.
Another endpoint that is subscribed to that topic will receive the message,
process it, and publish a response with a reference to the original message
id. The original sender then picks up this message and accepts it as the
response to their request. There's more going on there but that's the gist
of it. So which the request function is called I need the caller to block,
but not the MQTT client itself as it will still need to be processing
messages on the network.

On Fri, Sep 29, 2017 at 12:40 AM, 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
> http://erlang.org/mailman/listinfo/erlang-questions
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20171001/714834a5/attachment.htm>


More information about the erlang-questions mailing list