Can I handle any received message in gen_fsm state callbacks?
Asked Answered
P

1

1

I noticed that messages sent to the pid of a gen_fsm process are matched in the state callbacks as events. Is this just accidental or can I rely on this feature?

Normally I would expect general messages sent to a gen_fsm to show up in the handle_info/3 callback and thought I would have to re-send it using gen_fsm:send_event.

Does gen_fsm try to match the message first to the state callback and then allways with the handle_info/3 callback? Or only if it doesn't match a state callback clause?

However when I try it my message seems to be handled twice according to debug output.

So basically the question can also be stated like: how to correctly handle received messages as events in gen_fsm state functions?


Clarification: that some of the events are occurring by getting messages passed should be considered given for this question.

I'm aware that in many cases its cleaner to make the protocol visible by using function calls into the fsm only.

I'm not so sure if this would improve the current framework where the mentioned gen_fsm has to fit in: Diverse protocol stacks where each layer calls a connect() function to attach (and sometimes start) the lower layer. Packets are sent to lower layers ba calling a function (send) and received by receiveing a message. Much like gen_tcp.

By looking at the code for gen_fsm I already figured out that general messages are only passed to handle_info, so only the question remains wether to call the state function directly from the handle_info/3 callback or resent using gen_fsm:send_event.

Professionalism answered 18/10, 2010 at 19:5 Comment(4)
Have I understood you correctly here, are you using gen_fsm for only some of the protocol stack and not all of it? If so, why? Why not have all the Erlang part of the stack implemented in the same way? This would allow you to be consistent in how messages are sent and received.Southwestwardly
I'm consistently unsing a {ok, Pid} = connect(), send(Pid, Data) and receiving {resp, Data} messages. So I'm consistent in the API of different modules in the stack. Where I'm not consistent is the handling of receive and send currently.Professionalism
But there is quite a bunch of preexistent code using this paradigm so its an effort to change everything over. Reason for not using gen_fsm for all parts of the stack is that its actually very diverse protocols (automotive bus protocols) multiplexed over usb. So the parts of the stack vary between gen_server, simple ad/hoc server and stateless encode/decode filters and gen_fsm of course.Professionalism
I have picked up the suggestion for a better design of the whole protocol stack and started a new question to discuss how the best way would be to do this: "How to design a flexible Erlang protocol stack creation API" See "Linked" sectionProfessionalism
R
1

General messages are handled by handle_info callback, unless you have something like this in your code:

handle_info(Info, StateName, StateData) -> ?MODULE:StateName(Info, StateData).

Which avoids resending, but I do not recommend neither that, nor resending.

Delivering events exclusively by means of API calls encapsulating send_event/sync_send_event/send_all_state_event/sync_send_all_state_event makes protocol explicit. Which is a right thing, as it is easier to understand, maintain and document with edoc.

Razid answered 18/10, 2010 at 19:33 Comment(3)
The gen_fsm for now has to fit in a given architecture of protocol stacks, that are built along the pattern: lower levels are connect()ed by higher levels packets are sent() but are received by message sending to upper levels. Similar how gen_tcp handles connections. So either I change the whole pile of code to pass callbacks instead of messages for upstream, which I rather not currently or I have to handle these messages.Professionalism
Call directly - it's faster. Besides, in case of resending if API is used along with message passing you have no "sequential delivery from one source" guarantee.Razid
Thanks! I already implemented it as direct function call and it fits in nicely with the rest of the code. And it works like a breeze also.Professionalism

© 2022 - 2024 — McMap. All rights reserved.