Skip to content

Unable to use deferred_config with mix tasks #2

@aforward

Description

@aforward

I was looking for some guidance on how to properly use deferred_config when running mix tasks. In particular this is for running ecto tasks.

First, here is my test config.

use Mix.Config

config :myapp, Myapp.Repo, [
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_#{Mix.env}",
  username: {:system, "DB_USERNAME"},
  password: "",
  hostname: "localhost",
]

When I run iex -S mix, I properly see the env variable substituted.

iex(1)> Application.get_all_env :myapp
[{Myapp.Repo,
  [adapter: Ecto.Adapters.Postgres, database: "myapp_dev",
   username: "postgres", password: "", hostname: "localhost"]},
 {:ecto_repos, [Myapp.Repo]}, {:included_applications, []}]

But if I run mix ecto.create (for example), then the variable is not, as the application is not started, so the deferred injection isn't run.

$ mix ecto.create
Compiling 1 file (.ex)

07:19:22.351 [error] GenServer #PID<0.264.0> terminating
** (ArgumentError) argument error
    :erlang.iolist_size([<<0, 3, 0, 0>>, [[[], "user", 0, {:system, "DB_USERNAME"}, 0], "database", 0, "postgres", 0], 0])
    (postgrex) lib/postgrex/messages.ex:221: Postgrex.Messages.encode_msg/1
    (postgrex) lib/postgrex/protocol.ex:2018: Postgrex.Protocol.msg_send/3
    (postgrex) lib/postgrex/protocol.ex:551: Postgrex.Protocol.startup/2
    (postgrex) lib/postgrex/protocol.ex:475: Postgrex.Protocol.handshake/2
    (db_connection) lib/db_connection/connection.ex:134: DBConnection.Connection.connect/2
    (connection) lib/connection.ex:622: Connection.enter_connect/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: nil
State: Postgrex.Protocol
** (Mix) The database for Myapp.Repo couldn't be created: an exception was raised:
    ** (ArgumentError) argument error
        :erlang.iolist_size([<<0, 3, 0, 0>>, [[[], "user", 0, {:system, "DB_USERNAME"}, 0], "database", 0, "postgres", 0], 0])
        (postgrex) lib/postgrex/messages.ex:221: Postgrex.Messages.encode_msg/1
        (postgrex) lib/postgrex/protocol.ex:2018: Postgrex.Protocol.msg_send/3
        (postgrex) lib/postgrex/protocol.ex:551: Postgrex.Protocol.startup/2
        (postgrex) lib/postgrex/protocol.ex:475: Postgrex.Protocol.handshake/2
        (db_connection) lib/db_connection/connection.ex:134: DBConnection.Connection.connect/2
        (connection) lib/connection.ex:622: Connection.enter_connect/5
        (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

To work around this, I leveraged the init/2 function from Ecto

defmodule Myapp.Repo do
  use Ecto.Repo, otp_app: :myapp

  def init(_, config) do
    config
    |> DeferredConfig.transform_cfg
    |> (fn updated -> {:ok, updated} end)
  end

end

But I was wondering if there was a better way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions