Release Tasks - noproc Error

Hello there,

I am currently running into an issue with a release task (used to run database migrations after a new release has been deployed). For some reason it throws a noproc error on our server machine, despite working perfectly fine on my machine.
Apparently an application is not running, which does not seem to be true.

I’ll post the script and the output generated by our CD below:

release_tasks.ex

defmodule Sahnee.ReleaseTasks do

  @start_apps [
    :telemetry,
    :postgrex,
    :ecto
  ]

  def migrate() do
    IO.puts "Loading sahnee ..."
    # Load the code for sahnee, but don't start it
    :ok = Application.load(:sahnee)

    # Start apps necessary for executing migrations
    IO.puts "Starting dependencies #{inspect @start_apps} ..."
    Enum.each(@start_apps, fn(app) ->
      IO.puts " ... application #{app}"
      {:ok, _} = Application.ensure_all_started(app)
    end)

    # Start the Repo(s) for sahnee
    IO.puts "Starting repo ..."
    Sahnee.Repo.start_link()

    all_started = Application.started_applications()
    IO.puts "All started applications: #{inspect all_started}"

    # Run migrations
    run_migrations_for(:sahnee)

    # Run the seed script if it exists
    seed_script = seed_path(:sahnee)
    if File.exists?(seed_script) do
      IO.puts "Running seed script ..."
      Code.eval_file(seed_script)
    end

    # Signal shutdown
    IO.puts "Success!"
    :init.stop()
  end

  def priv_dir(app), do: "#{:code.priv_dir(app)}"

  defp run_migrations_for(app) do
    IO.puts "Running migrations for #{app} ..."
    Ecto.Migrator.run(Sahnee.Repo, migrations_path(app), :up, all: true)
  end

  defp migrations_path(app), do: Path.join([priv_dir(app), "repo", "migrations"])
  defp seed_path(app), do: Path.join([priv_dir(app), "repo", "seeds.exs"])
end

CD output:

+ ssh sahnee@sahneedestaging.sahnee.internal /opt/sahnee/build/bin/sahnee eval Sahnee.ReleaseTasks.migrate
Loading sahnee ...
Starting dependencies [:telemetry, :postgrex, :ecto] ...
 ... application telemetry
 ... application postgrex
 ... application ecto
Starting repo ...
All started applications: [
  {:ecto, 'A toolkit for data mapping and language integrated query for Elixir', '3.2.5'}, 
  {:postgrex, 'PostgreSQL driver for Elixir', '0.15.2'}, 
  {:db_connection, 'Database connection behaviour for database transactions and connection pooling\n', '2.1.1'}, 
  {:decimal, 'Arbitrary precision decimal arithmetic.', '1.8.0'}, 
  {:connection, 'Connection behaviour for connection processes\n', '1.0.4'}, 
  {:crypto, 'CRYPTO', '4.6.5'}, 
  {:telemetry, 'Dynamic dispatching library for metrics and instrumentations', '0.4.1'}, 
  {:logger, 'logger', '1.10.2'}, 
  {:elixir, 'elixir', '1.10.2'}, 
  {:compiler, 'ERTS  CXC 138 10', '7.5.3'}, 
  {:stdlib, 'ERTS  CXC 138 10', '3.12'}, 
  {:kernel, 'ERTS  CXC 138 10', '6.5.2'}
]
Running migrations for sahnee ...
** (exit) exited in: GenServer.call(Ecto.MigratorSupervisor, {:start_child, {{Ecto.Migration.Runner, :start_link, [{#PID<0.292.0>, Sahnee.Repo, Sahnee.Repo.Migrations.User, :forward, :up, %{level: :info, sql: false}}]}, :temporary, 5000, :worker, [Ecto.Migration.Runner]}}, :infinity)
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
    (elixir 1.10.2) lib/gen_server.ex:1013: GenServer.call/3
    lib/ecto/migration/runner.ex:21: Ecto.Migration.Runner.run/7
    lib/ecto/migrator.ex:342: Ecto.Migrator.attempt/7
    lib/ecto/migrator.ex:243: anonymous fn/4 in Ecto.Migrator.do_up/4
    lib/ecto/migrator.ex:324: anonymous fn/3 in Ecto.Migrator.run_maybe_in_transaction/6
    lib/ecto/adapters/sql.ex:898: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
    (db_connection 2.1.1) lib/db_connection.ex:1415: DBConnection.run_transaction/4
    lib/ecto/migrator.ex:323: Ecto.Migrator.run_maybe_in_transaction/6

It tries to call Ecto.MigrationSupervisor, which I’d assume should be started by the Ecto application. Do I have to take additional steps to be able to run migrations in a release task?

If I create a release on my machine using MIX_ENV=prod mix release and then run the release task everything works just fine.

Or is my approach wrong? It seems like a somewhat hacky solution. What is the standard approach to running migrations in a production environment which does not have access to the source code anymore?

Thanks for your time! :slight_smile:

You haven’t started :sahnee, which as your main app probably hosts the Repos supervision tree.

You need to either start your application or at least the Repo.

Hello,

thanks for your reply.

You need to either start your application or at least the Repo .

I do actually start the Repo:

# Start the Repo(s) for sahnee
    IO.puts "Starting repo ..."
    Sahnee.Repo.start_link()

However, I cannot start my :sahnee application for two reasons: (1) That’d run the application with the new code but and old schema and thus have a risk of causing strange behaviour and at worst data loss. (2) Also the application would at that point be accessible to users, despite not being ready yet.

It looks like the solution was that the :ecto_sql application was not running. I’ve included it and it seems like the deployment to our staging environment was successful. I’ll update the post once I can confirm this and our production environment is up and running.