Reputation: 1606
I have a GenServer
in a module called CameraServer
that fetches images which are then used by certain endpoints in the Phoenix Application.
defmodule MyApp.CameraServer do
@name :image_server
use GenServer
def start_link(_opts) do
IO.puts("Starting image server")
GenServer.start(__MODULE__, [], name: @name)
IO.puts("Image server started")
end
def get_images(_pid) do
GenServer.call(@name, :clear)
end
def get_images(_pid, mac_address) do
GenServer.call(@name, {:view, mac_address})
end
## Genserver Server Code
def init([]) do
images = ["image_0", ...]
{:ok, images}
end
def handle_call(:clear, _sender, state) do
{:reply, state, state}
end
def handle_call({:view, mac_address}, _sender, state) do
results = Enum.filter(state, &String.contains?(&1, mac_address))
{:reply, results, state}
end
end
And my application.ex
file is as follows.
defmodule MyApp.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
use Application
@impl true
def start(_type, _args) do
children = [
MyApp.CameraServer,
# Start the Ecto repository
MyApp.Repo,
# Start the Telemetry supervisor
MyApp.Telemetry,
# Start the PubSub system
{Phoenix.PubSub, name: MyApp.PubSub},
# Start the Endpoint (http/https)
MyApp.Endpoint
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
...
end
Now, when I run mix phx.server
, I will get the error
** (Mix) Could not start application myapp: MyApp.Application.start(:normal, []) returned an error: shutdown: failed to start child: MyApp.CameraServer ** (EXIT) :ok
Strange thing is that I am able to see in the logs the outputs:
Starting image server
Image server started
Additionally, I can also run iex -S mix phx.server
and then manually run MyApp.CameraServer.start_link([])
and then it works!
Upvotes: 0
Views: 435
Reputation: 8898
I think the problem in the MyApp.CameraServer.start_link/1
. You put IO.puts("Image server started")
as the last statement, and it returns :ok
, which is not a valid return value start_link/3
should return. It’s not a callback, hence it lacks an explicit contract, but implicitly it’d be added to the application supervision tree, which requires a proper return value to succeed.
You can change it to
def start_link(_opts) do
IO.puts("Starting image server")
case GenServer.start_link(__MODULE__, [], name: @name) do
{:ok, server} ->
IO.puts("Image server started")
{:ok, server}
error ->
IO.puts("Image server failed to start: #{inspect error}")
error
end
end
By the way, I changed GenServer.start
to GenServer.start_link
, because you want your CameraServer
process to link to its supervisor.
Upvotes: 3