Thinking about this more… so the Dockerfile’s default CMD is “foreground” (from Distillery). So in order to get things started up and seeded, I think I can do one of the following:
- If the
docker-compose.yml
specifies that our Elixir service depends_on
the database, then we can run it this way:
docker-compose run --rm myapp migrate
docker-compose run --rm myapp seed
docker-compose run up
That works but it always seems to kick off a few errors when the migrations are started:
05:14:53.970 [error] Postgrex.Protocol (#PID<0.146.0>) failed to connect: ** (DBConnection.ConnectionError) tcp connect (postgres:5432): connection refused - :econnrefused
05:14:53.970 [error] Postgrex.Protocol (#PID<0.145.0>) failed to connect: ** (DBConnection.ConnectionError) tcp connect (postgres:5432): connection refused - :econnrefused
and a few errors when the seeds are finished:
** (exit) exited in: GenServer.call(Mix.State, {:get, {Map, :get, [:env, :dev]}}, 5000)
** (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) lib/gen_server.ex:979: GenServer.call/3
(stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
(stdlib) erl_eval.erl:273: :erl_eval.expr/5
(stdlib) eval_bits.erl:88: :eval_bits.eval_field/3
(stdlib) eval_bits.erl:68: :eval_bits.expr_grp/4
(stdlib) erl_eval.erl:484: :erl_eval.expr/5
(stdlib) erl_eval.erl:232: :erl_eval.expr/5
(stdlib) erl_eval.erl:233: :erl_eval.expr/5
OR, if there is no depends_on
stipulation:
- In one tab, get the app running:
docker-compose run up
and in another, fire up the temporary images + commands:
docker-compose run --rm myapp migrate
docker-compose run --rm myapp seed
Which also works, but it gets the error upon conclusion of running the seeds.
And thirdly… the more I think about it, the more I think that there ARE cases where seeds should be included as migrations. I have a handful of behaviours that rely on dynamic dispatch, and the value that triggers the dispatch ultimately comes from the database. It’s not quite as on the nose as having a module name in the database (or some variant of polymorphism?), but we have situations where stuff like an order includes a unique string value representing say a vendor ID. And that vendor ID needs to trigger specific code to execute. So when we onboard a new vendor, we will have a new module (i.e. a new implementation of the order handling behaviour) and we’ll have a new row in the vendors
table. Those two things need to go out together. I realize that may be an edge case, but it really feels like a migration is the proper way to handle that particular seed.
Sorry – 3 things in that post, but I’d love to hear your thoughts.