In my Phoenix app, I need periodically sync some data stored in DB with an external service. So I add ExtSystem.Sync
module to execute this sync. Here is some code snippets:
application.ex
:
defmodule Core.Application do
# ...
use Application
def start(_type, _args) do
children = [
Core.Repo,
CoreWeb.Telemetry,
{Phoenix.PubSub, name: Core.PubSub},
CoreWeb.Endpoint,
ExtSystem.Sync
]
opts = [strategy: :one_for_one, name: Core.Supervisor]
Supervisor.start_link(children, opts)
end
# ...
end
sync.ex
:
defmodule ExtSystem.Sync do
use GenServer
# Client
def start_link([]) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end
# Server (callbacks)
@impl true
def init(state) do
send(self(), :sync) # error
# Process.send_after(self(), :sync, 1000) # ok
{:ok, state}
end
@impl true
def handle_info(:sync, state) do
# ...
Process.send_after(self(), :sync, period)
{:noreply, state}
end
# ...
end
If I send :sync
message from init
to ExtSystem.Sync
without any delay I got the next error:
14:04:36.724 [error] GenServer ExtSystem.Sync terminating
** (ArgumentError) errors were found at the given arguments:
* 2nd argument: not a key that exists in the table
(stdlib 3.15) :ets.lookup_element(Ecto.Repo.Registry, #PID<0.419.0>, 3)
(ecto 3.5.6) lib/ecto/repo/registry.ex:24: Ecto.Repo.Registry.lookup/1
(ecto 3.5.6) lib/ecto/repo/queryable.ex:210: Ecto.Repo.Queryable.execute/4
(ecto 3.5.6) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
(webtrit_core 0.2.0) lib/ext_system/sync.ex:34: ExtSystem.Sync.handle_info/2
(stdlib 3.15) gen_server.erl:695: :gen_server.try_dispatch/4
(stdlib 3.15) gen_server.erl:771: :gen_server.handle_msg/6
(stdlib 3.15) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Last message: :sync
State: %{}
When the supervisor starts ExtSystem.Sync
the second time everything works as expected. Also if I send :sync
message from init
to ExtSystem.Sync
with delay it also works as expected.
What is the correct way to wait for the full init of Ecto.Repo
before trying to execute requests?