William
William

Reputation: 4588

How to launch this Supervised GenServer as application

I have a working GenServer and working Supervisor. If I launch the Supervisor the GenServer is launched. If the GenServer is killed the Supervisor restarts it.

I am now trying to launch my code as an "Application". To do this I am changing code in my mix.exs file.

My entire code is below. The error I asm getting is at the very bottom

todos/lib/todos.exs

defmodule App.Service do
  use GenServer

  def start_link(state) do
    GenServer.start_link(__MODULE__, state, name: __MODULE__)
  end

  def init(state) do
     {:ok, state}
  end

  def get_state(pid) do
     GenServer.call(pid, :get_state)
  end

  def set_state(pid,state) do
     GenServer.call(pid, {:set_state, state})
  end


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


  def handle_call({:set_state, new_state}, _from, state)do
    {:reply,state,[new_state | state]}
  end
   
end

defmodule App.Supervisor do
  use Supervisor

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

  def init(_) do
     children = [
      {App.Service,[]}
     ]
  Supervisor.init(children, strategy: :one_for_one)
  end
end

todos/mix.exs

defmodule Todos.MixProject do
  use Mix.Project

  def project do
    [
      app: :todos,
      version: "0.1.0",
      elixir: "~> 1.14",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger],
      mod: {App, []}     # this is the only line I changed            
    ]
  end

  defp deps do
    [
    ]
  end
end

Error

[notice] Application todos exited: exited in: App.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function App.start/2 is undefined (module App is not available)
            App.start(:normal, [])
            (kernel 8.5) application_master.erl:293: :application_master.start_it_old/4
** (Mix) Could not start application todos: exited in: App.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function App.start/2 is undefined (module App is not available)
            App.start(:normal, [])
            (kernel 8.5) application_master.erl:293: :application_master.start_it_old/4

I am unsure what the App.start() method error is referring to, or how to fix this problem.

Upvotes: 0

Views: 580

Answers (1)

Everett
Everett

Reputation: 9638

Your mix.exs would need to reference a module that uses the Application module -- the convention is that this is the lib/your_app/application.ex, but that's just a convention. The referenced module just needs to have use Application. This is something like how the main function gets called in languages like Go or Rust, it's the entry point for the thing when it's running as an app.

Side note: I know this is an example for Stack Overflow, but do not name your applications using a generic name like App. That's a common convention in some languages/frameworks (e.g. PHP), but in Elixir, it's possible that you have multiple applications running in the same BEAM simultaneously, and they must each have unique names.

So the correct way to fix your code is to:

  1. replace your supervisor with an Application. (It's similar to a supervisor, but it's like THE supervisor). The Application is what would start your GenServer and anything else your app needs to run.
defmodule Todos.Application do

  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      {App.Service, []},
    ]

    opts = [strategy: :one_for_one, name: Todos.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

  1. And then update your mix.exs to reference the Todos.Application module:
  def application do
    [
      extra_applications: [:logger],
      mod: {Todos.Application, []}
    ]
  end

Upvotes: 3

Related Questions