2

So I have elixir program which runs in a loop and perform certain operations. I have declared an Agent to create a single zookeeper connection instance and then use the same in the loop. Following is my code:-

mix.exs

def application do
[ 
  applications: [:logger, :zookeeper],
  mod: {ServiceMonitor, []}
]

end    

defp deps do
[
  {:zookeeper, github: "vishnevskiy/zookeeper-elixir"}
]
end

service_monitor.ex

defmodule ServiceMonitor do
  def start(_type, _args) do
    {:ok, zk_agent} = Agent.start_link(fn -> ServiceMonitor.Registry.get_zk end)
    ServiceMonitor.Registry.start_process(zk_agent)
   end
end 

service_monitor/registry.ex

defmodule ServiceMonitor.Registry do
  alias Zookeeper.Client, as: ZK
  def start_process(zk) do

    pid = spawn_link(fn ->
        {:ok, data} = ZK.get_children(zk, "/test")
        IO.inspect(data)
    end)

    start_process(zk)

  end

  def get_zk do
    {:ok, zk} = ZK.start("localhost:2181")
    zk
  end
end

Now if I print the pid of the zk, i always get the same which means that the same instance of zk is returned always. But i am getting the following error:-

12:44:39.647 [error] GenServer #PID<0.165.0> terminating
** (stop) bad call: #Operation performed by zk
(elixir) lib/gen_server.ex:420: Agent.Server."handle_call (overridable 1)"/3
(stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:661: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: #
State: {:ok, #PID<0.166.0>} 

Also, if I always initialize the zk in loop instead of referencing from the agent, my code is working fine.

PS:- To reproduce it you need to have a zookeeper setup

Shubham Sharma
  • 175
  • 2
  • 16
  • Did you mean to return `zk` in `get_zk/0`? `{:ok, zk} = ZK.start(@zk_quorams)` -> `{:ok, zk} = ZK.start(@zk_quorams); zk`? If that doesn't fix it, could you please post an [MCVE](http://stackoverflow.com/help/mcve)? – Dogbert Sep 08 '16 at 07:29
  • Not able to solve by returning `zk` in get_zk/0. Have posted an MCVE. – Shubham Sharma Sep 08 '16 at 08:10
  • Try also changing `ZK.get_children(zk, "/test")` to `ZK.get_children(Agent.get(zk, &(&1)), "/test")`. – Dogbert Sep 08 '16 at 08:41
  • The error is gone, thanks. Now I am performing multiple operations in spawn_link eg:- I call a function in spawn_link which returns some value and is the input of the other function I call. When i do that, I get an error:- `(EXIT) an exception was raised: (SystemLimitError) a system limit has been reached`. – Shubham Sharma Sep 08 '16 at 10:30
  • Again pointing out, if I initialize zk everytime, my code works fine. – Shubham Sharma Sep 08 '16 at 10:36
  • Can you please add the new spawn_link code to the question? – Dogbert Sep 08 '16 at 12:34

1 Answers1

0

It seems that I was wrongly running the loop for the spawned process. Dogbert's solution on how to get the value returned by the agent in the loop actually worked. Now, I am running the loop on the spawned process as follows:-

def start_process(zk_agent) do
    spawn(ServiceMonitor.Registry, :start,[zk_agent])
    :timer.sleep(@sleep_time)
    start_process(zk_agent)
end

def start_process(zk_agent) do
    zk = Agent.get(zk_agent, &(&1))
    #Other logics
end
Shubham Sharma
  • 175
  • 2
  • 16