Start genserver automatically?

So I have a genserver that opens a message server.

defmodule MessageServer do
  use GenServer
 def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, [], opts)
  end

 # ... lot more functions
end

So to be able to start this, I have to enter iex and pattern match against MessageServer.start_link(table: messageserver_table) etc.
Can I somehow make this faster? so if I enter iex in this file or generally in this project, its starting that genserver automatically? maybe in the application child, im not sure about it though.

I tried the following:

children = [
MessageServer.start_link()
]

but errored,
21:06:58.812 [notice] Application messageserver exited: exited in: MessageServer.Application.start(:normal, [])
** (EXIT) an exception was raised:
** (ArgumentError) The module :ok was given as a child to a supervisor but it does not exist.
(elixir 1.14.0) lib/supervisor.ex:701: Supervisor.init_child/1
(elixir 1.14.0) lib/enum.ex:1658: Enum.“-map/2-lists^map/1-0-”/2
(elixir 1.14.0) lib/supervisor.ex:687: Supervisor.init/2
(elixir 1.14.0) lib/supervisor.ex:617: Supervisor.start_link/2
(kernel 8.5.2) application_master.erl:293: :application_master.start_it_old/4
** (Mix) Could not start application messageserver: exited in: MessageServer.Application.start(:normal, [])
** (EXIT) an exception was raised:
** (ArgumentError) The module :ok was given as a child to a supervisor but it does not exist.

Thanks!

You’re very close! This should be:

children = [
MessageServer
]

For more information, checkout the https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html guide

5 Likes

right, when I run iex -S mix in the application.ex, it normally opens iex shell. how can I connect to the genserver now? (start_link)

I suppose by connect you mean the PID of the genserver?

If you are planning on having only this genserver running, you can start it with name registration:

def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, [], name: MessageServer)
end

This doesn’t have to be the module name, you can use any atom, but you have to ensure that it is unique in your system.

In this way you can address the genserver from everywhere by the name you defined:

GenServer.call(MessageServer, :hello)
2 Likes

and the application stays the same? I also wonder why i> have to pass name:

When you start the genserver without passing name argument, you receive the response in the format of:

# Start the server
{:ok, pid} = GenServer.start_link(Stack, [:hello])

Where the pid is the local identifier you can address your genserver from:

GenServer.call(pid, :hello)

Now when you are starting your genserver from the application supervision, there is no easy way to get that pid, so it is easier to register your genserver with a global name, so you can reference it from iex just by the name you defined.

2 Likes

ok so in this example it doesnt make sense because I cant get the pid anywhere else? Instead of pattern matching it on the start_link() after iex’ing

You actually can by asking the supervisor about it. Your application supervisor will itself have a name like YourApp.Supervisor (check your application.ex file to be sure).

You can do:

Supervisor.which_children(YourApp.Supervisor)

You’ll see a list of tuples, and your genserver will be on that list, along with its pid. You can Enum.find on that list to get the pid.

2 Likes

hmm so I tried this and when entering iex, nothing really happens o.O

where do I have to paste that? below the
Supervisor.start_link(children, opts)?

I did try that and def start says

The inferred return type of start/2 
         ([{_,
            'restarting' | 'undefined' | pid(),
            'supervisor' | 'worker',
            'dynamic' | [atom()]}]) has nothing in common with 
          {'error', _} | {'ok', pid()} | {'ok', pid(), _}, which is the expected return type for the callback of the 'Elixir.Application' behaviour

putting it above wont work as it has to start first

Type that in iex. Don’t put it in application.ex.

If you look at the Name Registration documentation linked to above, you’ll see that there are multiple ways (limitless ways? as you can make your own) to name a process. There are also plenty of cases where you don’t need/want to name them, thus naming a GenServer is optional and how you do so is up to you.

1 Like

is the pid always the same?

No. It’s generated dynamically. That’s why you use a name if you want to easily find the process later.

1 Like

oh cool, yea, I got the following
[{Msg.Server, #PID<0.153.0>, :worker, [Msg.Server]}]

how can I automatically connect now? because running iex -S mix does nothing except for starting shell, I have to type everything on my own that takes lot of time xD

If there’s only going to be one Msg.Server and you want to easily send messages to it, then it’s best to name the process and address it that way. As described in Start genserver automatically? - #4 by D4no0