Heroku app recompiles after restarts using Elixir 1.15

For those coming here with a setup similar to mine:

  • Elixir 1.15
  • OTP 26
  • Heroku
  • Phoenix 1.7
  • And Umbrella app (4 apps)

The solution to make it work with Heroku, as explained previously, is to migrate to use Releases, but then, Node and npm weren’t being run so statics assets were not being compiled (i.e. apps/xxx/assets).

In the end I made it work in Heroku by adding a Procfile manually, keeping the Elixir and Phoenix static assets buildpacks, adding an additional “elixir mix release” buildpack and setting Phoenix Endpoint as a server.

Configuration step by step:

Phoenix Endpoint

I had a lot of trouble making Phoenix start in Heroku when building the mix release. In the end, this is what I needed to put inside config/runtime.exs. The secret lies in adding server: true, otherwise the Elixir release won’t start Phoenix as a server and Heroku will timeout on startup.

if config_env() == :prod do
  config :fb_web, Farmbackup.Endpoint,
    http: [
      port: {:system, "PORT"},
      compress: true,
      timeout: 60_000,
      protocol_options: [
        idle_timeout: 60_000
      ]
    ],
    url: [scheme: "https", host: System.fetch_env!("FARMBACKUP_HOST"), port: 443],
    debug_errors: false,
    cache_static_manifest: "priv/static/cache_manifest.json",
    secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),
    server: true
end

mix.exs release

In the main mix.exs file add all your umbrella apps in the releases config key:

  def project do
    [
      apps_path: "apps",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      aliases: aliases(),
      releases: [
        fb_task: [
          applications: [
            fb_web: :permanent,
            fb_db: :permanent,
            fb_invoice: :permanent,
            fb_salary: :permanent
          ],
          version: DateTime.utc_now() |> DateTime.to_iso8601()
        ]
      ]
    ]
  end

Heroku Buildpacks

You are going to need these 3 buildpacks installed in order:

https://github.com/HashNuke/heroku-buildpack-elixir.git
https://github.com/gigalixir/gigalixir-buildpack-phoenix-static
https://github.com/chrismcg/heroku-buildpack-elixir-mix-release

Buildpack config

elixir_buildpack.config

erlang_version=26.1.2
elixir_version=1.15.7
always_rebuild=false
runtime_path=/app

phoenix_static_buildpack.config

clean_cache=true
phoenix_relative_path=apps/fb_web (i.e. app in the umbrella which has `/assets`)
assets_path=apps/fb_web/assets
node_version=v14.15.5
npm_version=6.14.11

Procfile

YOU need to manually create a Heroku Procfile for Umbrellas.

In our case it is:

web: _build/prod/rel/fb_task/bin/fb_task start