Running ecto migration via release from distillery

You probably need to load your application before running the migrations.

Yes. In ReleaseTasks module I am trying to load application first, as you can see in my code:

def myapp, do: Application.get_application(:se)

But it is failing upon loading it. I also tried to run this via remote console:

iex(se_cloud@127.0.0.1)1> Application.get_application(:se)
nil

And getting this nil which means it is not able find application while I am able to run bin/se_cloud start without any error printed to console / logs.

I don’t think Application.get_application(:se) should return anything but nil unless you have defined :se module for some application.

What you should probably do is

def myapp do
  Application.get_application(__MODULE__) || raise("couldn't get application for #{__MODULE__}")
end

I’ve added a raise/1 here to “fail fast” in the case no application gets found. It would also provide us with a more constructive error message (couldn't get application for Se.ReleaseTasks) than what we’ve had before ({{badmatch,{error,{“no such file or directory”,“nil.app”}}}).

I was having problems with this exact line of code from the Distillery docs. I am pretty sure that Application.get_application doesn’t work at runtime in Distillery releases when you actually deploy them.

What I did is just hard-code my OTP app name like :myapp into the myapp function like so:

def myapp, do: :myapp

Besides the above, I don’t think your version is working since Application.get_application/1 takes in a module name. Something like MyApp.Foo. You can see this here: https://hexdocs.pm/elixir/Application.html#get_application/1.

It worked for me as well as I defined it as:

def myapp do
    :se
end

And now the seed is successfully run.

I am pretty sure that Application.get_application doesn’t work at runtime in Distillery releases when you actually deploy them.

I’ve just connected to a remote_console and run

iex(<app_name>@127.0.0.1)1> Application.get_application Web
:web

so it works for me at least.

The app is running in a docker container on k8s if that’s of any importance.

Did

def myapp do
  Application.get_application(__MODULE__) || raise("couldn't get application for #{__MODULE__}")
end

work for you?

@idiot After adding the raise part to code and executed I am getting this error:

{“init terminating in do_boot”,{#{‘exception’=>true,‘struct’=>‘Elixir.RuntimeError’,message=><<“couldn’t get application for Elixir.Se.Application”>>},[{‘Elixir.Se.ReleaseTasks’,myapp,0,[{file,“lib/release_tasks.ex”},{line,9}]},{‘Elixir.Se.ReleaseTasks’,seed,0,[{file,“lib/release_tasks.ex”},{line,16}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ({,[{Elixir.Se.ReleaseTasks,myapp,0,[{},{}]},{Elixir.Se.ReleaseTasks,seed,0,[{},{}]},{init,start_em,1,[]},{init,do_boot,3,[]}]})

Hm, maybe @bitwalker could know more.

Is this a release? Because this implies that this application was not included in the release.

And why is it “couldn’t get application for Elixir.Se.Application”. I would’ve expected “couldn’t get application for Elixir.Se.ReleaseTasks”, since that’s where I thought you would call this from.

Yeah it must work for some people since it’s in the Distillery docs but I’ve never been able to get it working without hardcoding my OTP app name. Whenever I test it Application.get_application/1 always returns nil.

Maybe you use that particular function incorrectly (it has a confusing name)? I would’ve named it Application.get_application_for_module/1.

Do any other functions from the Application module not work?

I’m pretty sure I’m not since I test it on a local iex session and it works fine but when I remote console into my app deployed with Distillery it does not. I can’t really test if any of the other functions from that module work right now however.

@idiot Once the release is started via bin/se_cloud start then I connected to remote_console and tried the following:

iex(se_cloud@127.0.0.1)6> :application.info[:running][:se]        
#PID<0.1972.0>
iex(se_cloud@127.0.0.1)7> :application.info[:running][:se_web]
#PID<0.2001.0>

So my applications seem to be running. I don’t know why we can’t get its information via Application.get_application(MODULE)

Have you tried

iex> Application.get_application(Se.ReleaseTasks)

in the same console?

Yes. Following is its output:

iex(se_cloud@127.0.0.1)1> Application.get_application(Se.ReleaseTasks)
:se

So it works. I don’t see why it wouldn’t work when called from myapp()

I got suspicious about Application.get_application. It says

The application is located by analyzing the spec of all loaded applications. Returns nil if the module is not listed in any application spec.

in the docs. So I tried

def myapp do
  app = Application.get_application(__MODULE__)
  if app do
    app
  else
    loaded_list() |> IO.puts
    raise("couldn't get application for #{__MODULE__}.")
  end
end

defp loaded_list, do: Application.loaded_applications |> Enum.map(fn {name, dis, ver} -> "#{name}, #{ver}" end) |> Enum.join("\n")

and this gave me

kernel, 5.3
stdlib, 3.4
elixir, 1.6.1
compiler, 7.1
iex, 1.6.1
{"init terminating in do_boot",{#{'__exception__'=>true,'__struct__'=>'Elixir.RuntimeError',message=><<"couldn't get application for......

where when you do the same thing from app console, you get a long list of loaded apps.

So this may mean that if you call the task, the app isn’t loaded, so you can’t do Application.get_application. Maybe this is umbrella-apps specific (if the examples in the docs works on normal phoenix apps)?

1 Like

I had the same problem with a normal, non-umbrella Phoenix app so I think it is just broken in general for some reason. It must work for some people though since it is on the Distillery docs but I don’t know why it wouldn’t work for many others.

1 Like