2
votes

I have a module named Tornado that implements a GenServer and I'm trying to spawn it as a process with a different name than the name of the module itself. According to the Elixir Docs a GenServer Process can be registered by giving an atom as a parameter

children = [
  worker(Tornado, [[], [name: :tornado_server]])
]

But when I try to call a function on it I get an error:

iex(2)> :tornado_server.send_requests 
** (UndefinedFunctionError) undefined function :tornado_server.send_requests/1 (module :tornado_server is not available)

I also tried to change :tornado_server to TornadoServer

** (UndefinedFunctionError) undefined function     TornadoServer.send_requests/1 (module TornadoServer is not available)

EDIT

Here is the Tornado Module

defmodule Tornado do
  use GenServer

  # Public API
  def start_link(state,  opts \\ []) do
    GenServer.start_link __MODULE__, state, opts
  end

  def send_requests(requests) do
    GenServer.cast(self, {:send_requests, requests})
  end

  def get_responses do
    GenServer.call(self, :get_responses )
  end

  # GenServer API
  def init(state) do
    # creaza 10 Ci
    { :ok, state }
  end

  def handle_cast({:send_requests, requests}, state) do
    state = state ++ [{requests, "127.0.0.1\n"}]
    {:noreply, state }
  end

  def handle_call(:get_responses, _from, state) do
    {:reply, state, state}
  end
end

And here is the Supervisor that starts it:

defmodule TornadoSupervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__,[])
  end

  def init([]) do
    children = [
      worker(Tornado, [[], [name: :tornado_server]])
    ]

    supervise(children, strategy: :one_for_one)
  end
end

Basically I would like to call it like this:

 > TornadoSupervisor.start_link
 > TornadoServer.send_requests some_requests_array
 > TornadoServer.get_responses

Later Edit Apparently it works if I do it like this

 > GenServer.cast(TornadoServer, {:send_requests,requests})
 > GenServer.call(TornadoServer, :get_responses )

But I find this syntax too verbose.

1

1 Answers

3
votes

Calling your function with :tornado_server.send_requests will look for the erlang module tornado_server which is unlikely what you want.

You still need to call the function on your module, the name is used in place of the pid, not the module name.

Without seeing your module, it is difficult to advise further. I would suggest reading http://elixir-lang.org/getting-started/mix-otp/genserver.html then http://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html to see how named processes work.

EDIT

GenServer.cast/call expect a pid (or registered name) as the first argument. The pid you are using (the result of self) is the caller, not the running GenServer.

You should either store the pid and do something like:

{:ok, pid} = Tornado.start_link()
Tornado.send_requests(pid, some_requests_array)
Tornado.get_responses(pid)

Or you should replace your implementation to use the provided name:

  def send_requests(requests) do
    GenServer.cast(:tornado_server, {:send_requests, requests})
  end

  def get_responses do
    GenServer.call(:tornado_server, :get_responses )
  end

It is not really clear why you don't want to use the module name though. It is a pretty common convention for a GenSever that you only want 1 of.