elixir - Can't reproduce "start/loop" behaviour in GenServer -
i'm trying use process synchronisation mechanism can receive messages our of order still act properly. i've managed implement simplified version of problem plain process, i'm failing achieve same effect genserver.
the simplified version this:
defmodule fun def start_link spawn(fn -> loop(:initiated) end) end def loop(state) receive :join when state == :initiated -> io.inspect("handling join") loop(:initiated) :finish when state == :initiated -> io.inspect("finishing") loop(:finishing) :cleanup when state == :finishing -> io.inspect("cleaning up...") end end end
the above process :join
, :finish
messages when state
:initiated
, , perform :cleanup
, exit when :finish
has been received. here i'm trying take advantage of messages being stuck in mailbox until can matched.
it works this:
iex(1)> pid = fun.start_link #pid<0.140.0> iex(2)> send(pid, :join) "handling join" :join iex(3)> send(pid, :join) "handling join" :join iex(4)> send(pid, :cleanup) # no `io.inspect` @ point :cleanup iex(5)> send(pid, :finish) # 2 `io.inspect`s once `:finish` received "finishing" :finish "cleaning up..."
i trying reproduce same behaviour genserver:
defmodule funserver use genserver def start_link genserver.start_link(__module__, :ok, name: __module__) end def init(:ok) {:ok, :initiated} end def handle_info(:join, msg) when msg == :initiated io.inspect("handling join [from genserver]") {:noreply, :initiated} end def handle_info(:finish, msg) when msg == :initiated io.inspect("finishing [from genserver]") {:noreply, :finishing} end def handle_info(:cleanup, msg) when msg == :finishing io.inspect("cleaning [from genserver]") {:stop, :normal, msg} end end
given configured application genserver :temporary
worker
works this:
iex(1)> send(funserver, :join) "handling join [from genserver]" :join iex(2)> send(funserver, :cleanup) :cleanup iex(3)> 07:11:17.383 [error] genserver funserver terminating ** (functionclauseerror) no function clause matching in funserver.handle_info/2 (what_the_beam) lib/fun_server.ex:22: funserver.handle_info(:cleanup, :initiated) (stdlib) gen_server.erl:616: :gen_server.try_dispatch/4 (stdlib) gen_server.erl:686: :gen_server.handle_msg/6 (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3 last message: :cleanup state: :initiated
i've tried using handle_cast
callbacks, , different format of arguments, like:
handle_info(:cleanup, :finishing)
or
handle_cast(:cleanup, :finishing)
instead of where msg == :finishing
, none of them worked me.
i'm using elixir 1.5 erlang 20.
the problem running called selective recieve of regular erlang processes. quote joe armstrong's book:
receive works follows: ... 2. take first message in mailbox , try match against pattern1, pattern2, , on. if match succeeds, message removed mailbox, , expressions following pattern evaluated. 3. if none of patterns in receive statement matches first message in mailbox, first message removed mailbox , put “save queue.” second message in mailbox tried. procedure repeated until matching message found or until messages in mail- box have been examined. 4. if none of messages in mailbox matches, process suspended , rescheduled execution next time new message put in mailbox. note when new message arrives, messages in save queue not rematched; new message matched. 5. message has been matched, messages have been put save queue reentered mailbox in order in arrived @ process. if timer set, cleared. 6. if timer elapses when waiting message, evaluate expressions expressionstimeout , put saved messages mailbox in order in arrived @ process.
gen_server not working way. needs callback module match message or found out there error thrown because gen_server implementation not finding way dispatch. if want gen_server implementation match logic of receive outlined above have manually. simple way accumulate messages can not match in given state in sort of list , resend them self() after each successful match. state can not simple atom anymore because need organize saved queue on own.
and btw same question asked before in context of erlang. responder had suggestion 1 one described. if need concrete code here link question: how do selective receives in gen_servers?
Comments
Post a Comment