<div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">It is documented behaviour for next_event:</div><br>This action does not set any transition_option() but instead stores the specified EventType and EventContent for insertion after all actions have been executed. <div><br></div><div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">My guess is that replies are sent as early as possible because this exposes concurrency to the maximum.</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">I would also be very cautious around relying on orderings like these in a system since that is where concurrency bugs are hidden.</div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jul 31, 2019 at 10:41 AM Peter Morgan <<a href="mailto:peter.james.morgan@gmail.com">peter.james.morgan@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;">Hi,<div><br></div><div>I regularly use the following pattern in gen_statem:</div><div><br></div><div><div>handle_event({call, From}, a, _, _) -></div><div> {keep_state_and_data, [{next_event, internal, work}, {reply, From, ok}]};</div></div><div><br></div><div>Where `work` is some side effect that needs to be done, and may be used by several other actions (hence wrapping it in a next_event) but the result is unimportant and doesn’t affect the reply. I use next_event rather than calling work() directly because it can be traced via sys.</div><div><br></div><div>My assumption was that work would be processed before the reply was sent to the caller - i.e., that the actions were processed in order.</div><div><br></div><div>Instead, it appears that the reply action is processed immediately?</div><div><br></div><div>To work around this I have started using:</div><div><br></div><div><div>handle_event({call, From}, a, _, _) -></div><div> {keep_state_and_data, [{next_event, internal, work}, {next_event, internal, {reply, From, ok}]}};</div></div><div><div>handle_event(internal, {reply, From, Result}, _, _) -></div><div> {keep_state_and_data, {reply, From, Result}}.</div></div><div><br></div><div>The above ensures that work is completed before the reply is sent (result of the work is a side-effect here) - but is a rather ugly solution.</div><div><br></div><div>Is the above intended behaviour? In some cases the `work` event causes state changes, or queueing subsequent other work (via next_event, internal) that was expected to be completed before the {reply, From, ok} was consumed.</div><div><br></div><div>The above ordering of actions assumption caught me out recently, the early reply was causing a process to be killed before it had actually completed its work causing an unclean shutdown in a system.</div><div><br></div><div>BTW the additional of log is very useful in failure analysis - what did this statem recently do? :) thanks!</div><div><br></div><div><br></div><div>Thanks,</div><div>Peter.</div><div><br></div><div>Full example:</div><div><br></div><div><div>-module(exaple_statem_reply).</div><div><br></div><div>-behaviour(gen_statem).</div><div>-export([a/0]).</div><div>-export([b/0]).</div><div>-export([callback_mode/0]).</div><div>-export([handle_event/4]).</div><div>-export([init/1]).</div><div>-export([start/0]).</div><div>-export([stop/1]).</div><div>-include_lib("kernel/include/logger.hrl").</div><div><br></div><div>start() -></div><div> gen_statem:start({local, ?MODULE},</div><div> ?MODULE,</div><div> [],</div><div> [{debug, [log, trace]}]).</div><div><br></div><div>a() -></div><div> gen_statem:call(?MODULE, ?FUNCTION_NAME).</div><div><br></div><div>b() -></div><div> gen_statem:call(?MODULE, ?FUNCTION_NAME).</div><div><br></div><div>stop(S) -></div><div> gen_statem:stop(S).</div><div><br></div><div>init([]) -></div><div> {ok, limbo, #{}}.</div><div><br></div><div><br></div><div>callback_mode() -></div><div> handle_event_function.</div><div><br></div><div>handle_event({call, From}, a, _, _) -></div><div> {keep_state_and_data, [nei(work), {reply, From, ok}]};</div><div><br></div><div>handle_event({call, From}, b, _, _) -></div><div> {keep_state_and_data, [nei(work), nei({reply, From, ok})]};</div><div><br></div><div>handle_event(internal, work, _, _) -></div><div> keep_state_and_data;</div><div><br></div><div>handle_event(internal, {reply, From, Result}, _, _) -></div><div> {keep_state_and_data, {reply, From, Result}}.</div><div><br></div><div>nei(Event) -></div><div> {next_event, internal, Event}.</div></div><div><br></div><div><br></div><div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">1> exaple_statem_reply:start().</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply enter in state limbo</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply consume internal init_state in state limbo</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">{ok,<0.161.0>}</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">2> exaple_statem_reply:a().</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply receive call a from <0.78.0> in state limbo</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply receive internal work in state limbo</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply send ok to <0.78.0></span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply consume call a from <0.78.0> in state limbo</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">ok</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">*DBG* exaple_statem_reply consume internal work in state limbo</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">3> sys:get_status(exaple_statem_reply).</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">{status,<0.161.0>,</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {module,gen_statem},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> [[{'$ancestors',[<0.78.0>]},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {'$initial_call',{exaple_statem_reply,init,1}}],</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> running,<0.161.0>,</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> [{trace,true},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {log,[3,</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{consume,{internal,work},limbo,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{consume,{{call,{<0.78.0>,</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> #Ref<0.2400559651.2919759873.28633>}},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> a},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> limbo,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{out,ok,{<0.78.0>,#Ref<0.2400559651.2919759873.28633>}},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{in,{internal,work},limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{in,{{call,{<0.78.0>,#Ref<0.2400559651.2919759873.28633>}},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> a},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{consume,{internal,init_state},limbo,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {{enter,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> exaple_statem_reply,#Fun<gen_statem.1.50707408>}]}],</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> [{header,"Status for state machine exaple_statem_reply"},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {data,[{"Status",running},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {"Parent",<0.161.0>},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {"Logged Events",</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> [{enter,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {consume,{internal,init_state},limbo,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {in,{{call,{<0.78.0>,#Ref<0.2400559651.2919759873.28633>}},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> a},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {in,{internal,work},limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {out,ok,{<0.78.0>,#Ref<0.2400559651.2919759873.28633>}},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {consume,{{call,{...}},a},limbo,limbo},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {consume,{internal,work},limbo,limbo}]},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {"Postponed",[]}]},</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures"> {data,[{"State",{limbo,#{}}}]}]]}</span></div><div style="margin:0px;font-stretch:normal;font-size:14px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures">4> </span></div></div><div><span style="font-variant-ligatures:no-common-ligatures"><br></span></div><div><br></div></div>_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature">J.</div>