Timeout error when communicating between gen_servers via pid

40 views
Skip to first unread message

J David Eisenberg

unread,
May 14, 2013, 1:16:17 AM5/14/13
to elixir-l...@googlegroups.com
This gist: https://gist.github.com/jdeisenberg/5573843 is nearly the minimal code I could develop to demonstrate the problem.  Here are the steps I used to duplicate the problem, with Erlang R16B (erts-5.10.1) and Interactive Elixir (0.8.3.dev).

I have a Central server and multiple "Person" servers. A person can register her user name (and pid) with the Central server. Each Person also has a piece of information in his state. Person A can get person B's information by asking the server to retrieve it.

Open a terminal window and type:
    iex --sname central
    c("servertest.ex")
    Central.start_link

Open a second terminal window and type:
    iex --sname sales
    Person.start_link("Spain")
    :gen_server.call({Central, :central@localhost}, {:register, "Steve"})

Open a third terminal window and type:
    iex --sname marketing
    Person.start_link("Monaco")
    :gen_server.call({Central, :central@localhost}, {:register, "Michele"})

Return to the first terminal. Explicitly call for Michele's info
by using a {Name, Node}:

    :gen_server.call({Person, :marketing@localhost}, :get_info)

The response shows that marketing is listening.

Now go to the second terminal window (Steve in sales) and try
getting the information by sending Central a message to get Michele in marketing's info.

    :gen_server.call({Central, :central@localhost}, {:info, "Michele"})

...and we get a timeout, but looking at the output from the central server, it seems that the PID for marketing is correct.

    Central gets request from #PID<7777.32.0> to register Steve
    Central gets request from #PID<7806.32.0> to register Michele
    iex(central@localhost)2> :gen_server.call({Person, :marketing@localhost}, :get_info)
    ["Monaco"]
    Central gets request for info about Michele from {#PID<7777.32.0>,#Reference<7777.0.0.75>}
    Central sends info request to #PID<7806.32.0>
    iex(central@localhost)3>
    =ERROR REPORT==== 13-May-2013::22:04:06 ===
    ** Generic server 'Elixir-Central' terminating
    ** Last message in was {info,<<"Michele">>}
    ** When Server state == [{<<"Michele">>,<7806.32.0>},
                             {<<"Steve">>,<7777.32.0>}]
    ** Reason for termination ==
    ** {timeout,{gen_server,call,[<7806.32.0>,get_info]}}

In case you're wondering, "well why don't you just call via {module_name, node} instead of pid?" The reason is that there could be several Persons all using the same node, and the only way to get the person I want is by her unique pid.

Yurii Rashkovskii

unread,
May 14, 2013, 1:32:51 AM5/14/13
to elixir-l...@googlegroups.com
From a brief look at the code, the problem lies in the fact that you are using caller's PID as what you later assume will be Person's PID. Because of this, :gen_server.call(pid, :get_info) will call into your shell, which *will* result in a timeout as shell won't respond to this:

iex(1)> :gen_server.call(self, :get_info)
** (exit) {:timeout,{:gen_server,:call,[#PID<0.26.0>,:get_info]}}






--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

J David Eisenberg

unread,
May 14, 2013, 1:51:46 AM5/14/13
to elixir-l...@googlegroups.com


On Monday, May 13, 2013 10:32:51 PM UTC-7, Yurii Rashkovskii wrote:
From a brief look at the code, the problem lies in the fact that you are using caller's PID as what you later assume will be Person's PID. Because of this, :gen_server.call(pid, :get_info) will call into your shell, which *will* result in a timeout as shell won't respond to this:

iex(1)> :gen_server.call(self, :get_info)
** (exit) {:timeout,{:gen_server,:call,[#PID<0.26.0>,:get_info]}}

Ah, OK; that makes sense. Is there some sort of work-around to get the true PID?

Yurii Rashkovskii

unread,
May 14, 2013, 2:02:34 AM5/14/13
to elixir-l...@googlegroups.com
Yes, pass it in the message you're sending to register a Person. You might want to implement a `{:register, central}` call in Person to make it a little easier to use (so that the Person process itself will just pass its own pid to `central`)

J David Eisenberg

unread,
May 14, 2013, 10:49:54 AM5/14/13
to elixir-l...@googlegroups.com


On Monday, May 13, 2013 11:02:34 PM UTC-7, Yurii Rashkovskii wrote:
Yes, pass it in the message you're sending to register a Person. You might want to implement a `{:register, central}` call in Person to make it a little easier to use (so that the Person process itself will just pass its own pid to `central`)

I realized that what has to happen is that the shell has to do :gen_server.call(Person, {:register, user_name}). Person's handle_call has to catch that and forward it in a :gen_server.call to Central. That works because Central is getting the message from Person, not the shell that started Person.
Reply all
Reply to author
Forward
0 new messages