How to create module-based simple_one_for_one supervisor?

I’m working on an application that will dynamically launch a port process. The port is a video player but that’s not important. What I’m interested in is how to supervise these dynamic, short-lived(30sec-5min) worker processes. Reading about about supervisors it sounds like what I want is a simple_one_to_one supervisor.

But i can’t figure out how to make one! For example, when I try to use this implementation the phoenix server won’t start, complaining about Ecto? Does anyone have a hint or an example of a module based simple_one_for_one supervisor that accepts a child_spec and passes arguments to the worker?

thanks!

defmodule Exopticon.PlaybackSupervisor do
  use Supervisor

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

  def init(_) do
    child_spec = %{
      start: {Exopticon.PlaybackPort, :start_link, []},
      restart: :transient,
      shutdown: 5000,
      type: :worker
    }

    Supervisor.init(child_spec, strategy: :simple_one_for_one)
  end
end
* (Mix) Could not start application exopticon: exited in: Exopticon.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) repo Exopticon.Repo is not started, please ensure it is part of your supervision tree
            (ecto) lib/ecto/query/planner.ex:136: Ecto.Query.Planner.query_lookup/6
            (ecto) lib/ecto/query/planner.ex:119: Ecto.Query.Planner.query_with_cache/7
            (ecto) lib/ecto/repo/queryable.ex:122: Ecto.Repo.Queryable.execute/5
            (ecto) lib/ecto/repo/queryable.ex:35: Ecto.Repo.Queryable.all/4
            (exopticon) lib/exopticon/application.ex:29: Exopticon.Application.start/2
            (kernel) application_master.erl:273: :application_master.start_it_old/4
1 Like

The message is telling You something different. It means Repo is not started. In your main supervisor, You should have something like this…

  def start(_type, _args) do
    import Supervisor.Spec, warn: false
    
    children = [
      supervisor(Exopticon.Repo, [])
    ]

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

Then, in your PlaybackSupervisor, You should have something like this…

  def start_child(initial_state) do
    Supervisor.start_child(__MODULE__, [initial_state])
  end

  def init(_) do
    children = [
      worker(YourWorker, [], restart: :temporary)
    ]
    supervise(children, strategy: :simple_one_for_one)
  end
3 Likes

Looks like you have a good answer, but just to add plenty of examples for some of the functionality you want and then some. These are all supervised via simple_one_to_one, except timer, and used in a phoenix project (which doesn’t really matter)

Supervisors - https://github.com/smileys-tavern/smileys_data/tree/master/lib/state

Genservers:
/post - registered globally and kills itself (timeout) after 3 days
/room - registered globally and expires (reverses) it’s activity counts after 12 hours
/user - similar to room with a few extra behaviors and different state structure
/timer - handles expirey for room/user because a local process was easier to use here. not needed for self expirey

I’m still learning myself and refer to Erlang and OTP in Action to try and brush up me fundamentals

2 Likes

Thanks koko and subetei for the help. Now I’m looking at the documentation for Supervisor.Spec that contains the “supervise” and “worker” functions you both use and it has a scary deprecation warning at the top.

What does that mean? Do your examples work with Elixir 1.5? I will try it and see.

Thanks again!

1 Like

They will probably work until elixir 2.0, but from 1.5 on you will get a warning.

1 Like