Accessing an Ecto Repo inside of a Mix Task in Phoenix

The Phoenix documentation at the bottom of this page says that to access the Ecto Repo from within a Mix.Task I can just use @requirements ["app.config"]. That didn’t work for me, but just calling Ecto.Migrator.with_repo/2 did. Are the docs out of date? I’d be happy to write a PR if so!

defmodule Mix.Tasks.App.Ingest do
  use Mix.Task
  @impl Mix.Task
  def run(_args) do
    {:ok, _, _} = Ecto.Migrator.with_repo(App.Repo, fn (_repo) ->
      IO.inspect App.Repo.all(App.SomeModel)
    end)
  end
end

Not sure if that backtick placement was a typo or not—ie, use @requirements ["app.config"] vs just @requirements ["app.config"]. However, I’m not sure if that is a typo or outdated docs or whatnot (or just a different use case) but to use my repo I always do:

@requirements ["app.start"]
def run(_), do: ...

And welcome to the forums!

2 Likes

Hi @sodapopcan, thanks for your reply!!

@requirements ["app.start"] does indeed work! Thank you!

The docs say @requirements ["app.config"] should work, but it doesn’t:

→ mix task.name
Compiling 1 file (.ex)
** (RuntimeError) could not lookup Ecto repo App.Repo because it was not started or it does not exist
    (ecto 3.11.1) lib/ecto/repo/registry.ex:22: Ecto.Repo.Registry.lookup/1
    (ecto 3.11.1) lib/ecto/repo/supervisor.ex:160: Ecto.Repo.Supervisor.tuplet/2
    (kaiten 0.1.0) lib/kaiten/repo.ex:2: App.Repo.all/2
    (kaiten 0.1.0) lib/mix/tasks/kaiten.ingest.ex:13: Mix.Tasks.App.Ingest.run/1
    (mix 1.16.0) lib/mix/task.ex:478: anonymous fn/3 in Mix.Task.run_task/5
    (mix 1.16.0) lib/mix/cli.ex:96: Mix.CLI.run_task/2
    /Users/jyc/.asdf/installs/elixir/1.16.0-otp-26/bin/mix:2: (file)

I’ll submit a PR to fix the docs. Thank you s omuch for the help!

2 Likes

PR: Fix broken reference to app.config in "Creating our own Mix task" docs by jyc · Pull Request #5695 · phoenixframework/phoenix · GitHub

4 Likes

There is a little bit of nuance that makes me prefer explicit calls to Ecto.Migrator.with_repo if genuinely all you’re doing in the body of the Mix task is some SQL DML statements. The concern is that if any aspect of your full/default application supervision tree starts to immediately do meaningful work, such as Oban or cluster peering, that will fire up in the background of your Mix task if you use app.start and don’t take further preventative steps. This can be detrimental or at very least wasteful of resources, and you’d better hope that the code in question has reasonable behavior for graceful shutdown since it will probably stop the BEAM ~immediately if your Mix task is brief.

If those concerns would apply to your project, with_repo is nicely precise and intention-revealing IMO and doesn’t have this downside. You can still insert Oban jobs in this context as well, without allowing queues to start.

2 Likes

Oh interesting. Never thought of this before, thanks!