Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to put service/initialization code in an Elixir/Mix/Phoenix app?

I have an Elixir/Mix app (also Phoenix, but plenty of non-Phoenix stuff in there too), and I'm wondering what the best practices are for putting in "startup" code, things like dynamically adding children to supervisors, firing off "I'm alive!" pings, or other things that you want to happen immediately after startup.

One obvious place is the Application file, but the expected return there is the return from Supervisor.start_link(children, opts). So, for example, in a Phoenix app, I could do this:

defmodule MyApp do
  use Application

  def start(_type, _args) do
    import Supervisor.Spec

    children = [
      supervisor(MyApp.Repo, []),
      supervisor(MyApp.Endpoint, []),
      supervisor(MyApp.DynamicSupervisorThingy, [])
    ]
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    start_val = Supervisor.start_link(children, opts)



    # --- Put things right here that I want to start ----
    MyApp.DynamicSupervisorThingy.add_children_dynamically()
    MyApp.SomeModule.do_some_thingy()
    MyApp.OtherModule.send_some_pings()
    if MIX_ENV == :prod do
      MyApp.YetAnother.prod_stuff_i_dont_want_in_dev()
    end


    start_val
  end
end

This seems wrong, but I can't figure out where I'm supposed to be putting this code.

like image 921
Micah Avatar asked Apr 11 '17 15:04

Micah


1 Answers

It's totally fine. You Phoenix application is just an OTP application and you're allowed to shoot yourself in the foot however you want. Application.start just expects an {:ok, pid} tuple which is basically the application's top-level process.

I usually put my custom startup code first, then setup the main supervisor specification and start that supervisor - note that if you have ordering dependencies between your "dynamic supervisor" being started and applications being added, like it seems to be the case above, you may lose out because of timing stuff - I'd properly configure that supervisor in its specification so it can do things in its init callback, but I don't know your code or your requirements.

In any case, the Application.start is all yours, as long as you abide by its contract :-)

like image 161
cdegroot Avatar answered Oct 29 '22 16:10

cdegroot