SSL connection cannot be established using elixir releases

I am using elixir releases to deploy my app to digital ocean. I need to run my migrations so that I can setup my tables in postgres. I followed the directions listed in the Phoenix docs related to ecto migrations and custom commands. However when I attempt to run the command (replacing my_app with the name of my app): _build/prod/rel/my_app/bin/my_app eval "MyApp.Release.migrate" I get this error:

** (RuntimeError) SSL connection can not be established because `:ssl` application is not started,
you can add it to `extra_application` in your `mix.exs`:

  def application do
    [extra_applications: [:ssl]]
  end

        (postgrex) lib/postgrex.ex:538: Postgrex.ensure_deps_started!/1
        (postgrex) lib/postgrex.ex:480: Postgrex.child_spec/1
        (ecto_sql) lib/ecto/adapters/sql.ex:459: Ecto.Adapters.SQL.init/3
        (ecto) lib/ecto/repo/supervisor.ex:162: Ecto.Repo.Supervisor.init/1
        (stdlib) supervisor.erl:295: :supervisor.init/1
        (stdlib) gen_server.erl:374: :gen_server.init_it/2
        (stdlib) gen_server.erl:342: :gen_server.init_it/6
        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Following the advice of the error I update my mix.exs file.

  def application do
    [
      mod: {MyApp.Application, []},
      extra_applications: [:logger, :runtime_tools, :ssl]
    ]
  en

I run MIX_ENV=prod mix compile, then MIX_ENV=prod mix release, then _build/prod/rel/my_app/bin/my_app eval "MyApp.Release.migrate" again and I still get the same error above related to not having the :ssl application started.

I sense I am missing something but I don’t quite know what it is. Any help is greatly appreciated.

5 Likes

Can you run migration with that command on your dev environment?
If you can, then the issue may related to your production environment setup.

I will give it a try

I get the same :ssl is not started error from above when I run it on my machine (not on the DO server).

What I reckon happens is that the migration file is run by the eval command outside the normal application startup system (or rather, without it). So it doesn’t load or start what is defined in mix.exs. As you can see in the code, it loads your application manually, and it uses Ecto.Migrator.with_repo/3 that manually starts the Ecto repo(s). So adding :ssl to mix.exs won’t help.

Instead you could use Application.ensure_started(:ssl) at the top of your migration and rollback functions and see if that helps.

2 Likes

This is the correct solution. Once I put Application.ensure_all_started(@app) I was able to run my migrations without error. Now I will need to figure out what that does haha.

I got the idea for Application.ensure_all_started(@app) from here: Error: DBConnection.ConnectionError, ssl_not_started

Note that Application.ensure_all_started/1 will also start your application, so since it’s a Phoenix app it will start the whole server and any other child processes you have specified in your supervisor. You might not want to do that when running a migration, so you could try just Application.ensure_started/1 to selectively start only the apps you need.

6 Likes

@Nicd Thanks for the clarification. I will use Application.ensure_started/1 instead.

Did you ever get it to work with Application.ensure_started/1? I tried Application.ensure_started(:ssl) and Application.ensure_started(@app) and neither worked. Only Application.ensure_all_started(@app) worked.

If you use Application.ensure_started/1 you will need to figure out and start dependencies of that application on your own. If though you do Application.ensure_all_started/1 the BEAM will figure out dependencies for you and start them.

Therefore using Application.ensure_all_started/1 should be totally fine. Unless you call it with your application, or an application that depends on yours, it shouldn’t start your application.

I just tried Application.ensure_all_started(:ssl) and that worked.

6 Likes

Where did you put this line?

He probably put it in the MyApp.Release.migrate/0 function, as this would make most sense, since it is the entrypoint given in the OP.

1 Like
defmodule Foo.Release do
  @app :foo

  def migrate do
    ensure_started()

    for repo <- repos() do
      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
    end
  end

  def rollback(repo, version) do
    ensure_started()
    {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
  end

  defp repos do
    Application.load(@app)
    Application.fetch_env!(@app, :ecto_repos)
  end

  defp ensure_started do
    Application.ensure_all_started(:ssl)
  end
end
6 Likes

Thank you!

1 Like

This solved the problem