How do I fix this error when trying to create an "Application"

I tried to learn Elixir a few years ago and stopped. I am trying again.
In the code below I have a GenServer that is started by a Supervisor. When I compile the code it works as expected - if the GenServer is manually killed the Supervisor restarts it.

This is good and does what I expect.

I now want to wrap my code as an “Application”.

Thus I go to mix.exs and in the application method I update the code to reference my Module

def application do
    [
      extra_applications: [:logger],
      mod: {App, []}
    ]
  end

When I compile my code I get the following error:

18:49:32.437 [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 not sure what the error is inferring is wrong nor do I know how to fix it. I would like to know how to fix it and why the error occurs.

My full code is below

todos/lib/todos.ex




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/lib/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, []}
    ]
  end

  defp deps do
    [
    ]
  end
end

An application need to implement the Application behavior. You may want to see what the mix generator generate for you:

mix new hello_world --sup

And start from there.

1 Like

Just curious, Is there a way to do that retroactively to a preexisting mix instance?

btw, thank you. I updated the application.exs file that came with the install and it seems to have fixed my problem

Yeah you can. Just make two identical projects – one without --sup and one with – and check the differences. You can then manually apply them to any project without the supervisor / application switch.