Module not being loaded in umbrella app, even though the app it lives in has started and loaded

I have an umbrella app, with two applications inside - one an OTP app, the other a library app (the kind generated by doing mix new app inside the app folder in an umbrella. The library app requires the OTP app.

I want to create a command that can run on a distillery release (the way you may want to run migrations as outlined here

The command is defined inside of the library app and calls a function inside the otp app which calls String.to_existing_atom. The atom exists but it is defined inside a different module, inside the OTP app.

When I start the umbrella app with iex -S mix and run the command, everything works fine.

When I make a release in prod mode and run the command, it fails with:

Evaluation failed with: argument error
:erlang.binary_to_existing_atom("existing_atom", :utf8)

I create a release and run the command like this:

rm -rf _releases && MIX_ENV=prod  mix release --env=prod --name=base && MIX_ENV=prod  ./_releases/base/bin/base eval 'Elixir.LibraryApp.ReleaseTasks.task'

And the release task looks like this:

defmodule LibraryApp.ReleaseTasks do
  @deps [:otp_app, :logger]

  def task() do
    prepare_dependencies()
    LibraryApp.task()
    shutdown()
  end

  defp prepare_dependencies do
    Application.load(:library_app)
    Enum.each(@deps, fn x -> {:ok, _} = Application.ensure_all_started(x) end)
    Application.loaded_applications() |> IO.inspect()
    Application.started_applications() |> IO.inspect()
  end

  defp shutdown do
    :init.stop()
  end
end

I have created an example, minimal test case app here

It feels like the modules are being lazy loaded, but I don’t understand how to not have that? Is it a feature or a bug??

While this is not quite a solution to your problem, here is how one person dealt with a similar issue. https://nietaki.com/2018/12/04/string-to-existing-atom-is-a-double-edged-sword/

I wish I knew more about how release and module loading works, but you’ll have to wait for someone else to help with that aspect.

1 Like