Search code examples
elixirectoerlang-otpgen-server

Passing an env. variable dynamically to Application module, at runtime?


In my opt application I have some stuff that gets run on application boot:

    defmodule MyApp.Application do
      use Application

      def start(_type, _args) do
        children = [
          {Phoenix.PubSub, [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2]},
          {MyAppLib.Repo, []},
          {MyAppWeb.Endpoint, []},
          {MyAppLib.Cache, []},


          # these are GenServer-s, some may work with a database

          {MyApp.Worker1, []},      # 1 
          {MyApp.Worker2, []},      # 2
          {MyApp.Initializer, []}   # 3

        ]

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

However, I've found out that whenever I deploy the app on a new server, it'll fail to start up because a database hasn't been created yet. And even starting the application via console won't solve the problem because it'll still crash due to the same reason.

How to fix it?


Should I introduce a boolean env. variable "disable_db_related_workers" which I'd set to 'true' only when running the app the first time on a new server? Then I'd run console and from it I'd run the migrations.

$ MIX_ENV=prod DISABLE_DB_WORKERS=true ~/my_apps/my_app1/bin/my_app1 console

If so, how to do this properly inside Application then? It'll have to be evaluated at runtime, that is, not at compilation.


Solution

  • Ecto.Migrator.up/4 is your friend.

    It might be called from Application.start/2 directly because it’s idempotent. It might be called before starting the application right after deploy.

    Besides this advice, the real implementation is actually a matter of taste.