How to set up Telemetry properly in a mix task?

I have created a mix task for some bulk data update I want to do from the CLI with code like this:

defmodule Mix.Tasks.ApparatGenerateAll do
  alias Apparat.Repo

  use Mix.Task

  @shortdoc "Trigger generation for all"
  def run(_) do
    [:logger, :telemetry, :postgrex, :ecto]
    |> Enum.each(&Application.ensure_all_started/1)

    Repo.start_link()

    # Something that runs database queries here.
  end
end

This works as it should, but it also spews a whole bunch of errors to the console, like this one

15:27:25.871 [error] an exception was raised logging %DBConnection.LogEntry{call: :prepare_execute, connection_time: 681000, decode_time: 12000, params: [snip], pool_time: 34000, query: %Postgrex.Query{cache: :statement, columns: nil, name: "ecto_insert_oban_jobs", param_formats: nil, param_oids: nil, param_types: nil, ref: nil, result_formats: nil, result_oids: nil, result_types: nil, statement: "INSERT INTO \"oban_jobs\" (\"args\",\"attempt\",\"errors\",\"max_attempts\",\"queue\",\"state\",\"worker\") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING \"id\"", types: nil}, result: {:ok, %Postgrex.Query{snip}, %Postgrex.Result{columns: ["id"], command: :insert, connection_id: 960, messages: [], num_rows: 1, rows: [[196]]}}}: ** (ArgumentError) argument error
    (stdlib) :ets.lookup(:telemetry_handler_table, [:apparat, :repo, :query])
    /Users/mikl/Work/Ablis/kartotekov/deps/telemetry/src/telemetry_handler_table.erl:47: :telemetry_handler_table.list_for_event/1
    /Users/mikl/Work/Ablis/kartotekov/deps/telemetry/src/telemetry.erl:114: :telemetry.execute/3
    lib/ecto/adapters/sql.ex:805: Ecto.Adapters.SQL.log/4
    (db_connection) lib/db_connection.ex:1377: DBConnection.log/5
    (postgrex) lib/postgrex.ex:198: Postgrex.query/4
    lib/ecto/adapters/sql.ex:666: Ecto.Adapters.SQL.struct/10
    (ecto) lib/ecto/repo/schema.ex:651: Ecto.Repo.Schema.apply/4

So as far as I can tell, there’s something going wrong with Telemetry, since the very same queries work fine when run inside the Phoenix server. I tried adding :telemetry or :telemetry_app to the list of apps to start, but that appears to make no difference. How can I set up my mix task so Telemetry doesn’t throw a fit whenever I run a database query?

Starting :ecto_sql and the repo should actually be enough to start everything.

Something like this:

{:ok, _} = Application.ensure_all_started(:ecto_sql)
{:ok, _} = Repo.start_link()

What happens when you give it a try?

If that doesn’t work, try removing _build just in case.

2 Likes

That doesn’t start Postgrex for some reason, but adding

 {:ok, _} = Application.ensure_all_started(:postgrex)

before starting :ecto_sql fixes that.

So with that, it works. Thanks for the help.

1 Like

Depending on your Ecto version and the use-case, you might also appreciate the behavior of Ecto.Migrator.with_repo/3, which is not just for migrations. I believe @dpehrson in Slack first introduced me to it. I believe it was introduced in 3.1.2.

https://hexdocs.pm/ecto_sql/3.2.0/Ecto.Migrator.html#with_repo/3

2 Likes