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??