I’m working on an app that uses both
Ecto. The common pattern is to use
Cachex.fetch to wrap database queries, something like
Cachex.fetch(MyCache, "key", fn key -> database_query_by(key) end)
where the value is returned from cache when available, otherwise it calls the fallback function.
This is working fine when running the app, but it’s proving difficult to test because of the subtleties around Ecto Sandbox processes. Tests fail with a long error:
cannot find ownership process for #PID<0.1708.0>. The error message is thankfully very detailed, but I can’t seem to find a way to run these tests async because the only way I can get them to work is by running them in shared mode (i.e. with
The test setup that works is:
setup tags do repo_pid = Sandbox.start_owner!(MyRepo, shared: not tags[:async]) on_exit(fn -> Sandbox.stop_owner(repo_pid) end) :ok end
This ensures that the repo process is shared when the test module includes
async: false. With a little snooping around, I can see that
Cachex relies on
GenServer.call/3 to execute the fallback function, so it’s happening in its own process. I was hoping to allow this process explicitly, e.g.
allow = Process.whereis(MyCache) Ecto.Adapters.SQL.Sandbox.allow(MyRepo, self(), allow)
But that doesn’t work because the process identifying the cache is not the process executing these callback functions, so the above still gets the
cannot find ownership process for #PID<0.1708.0> errors. I think the crux of the matter is in
Cachex.Services.Courier.handle_call/3 where the fallback function is executed inside an ad-hoc
spawn/1 block. It’s not a named process, so you can’t “allow” it via
Ecto.Adapters.SQL.Sandbox.allow/3. You can put an
IO.inspect(self()) inside a
Cachex.fetch fallback function and see that the pid changes each time you run it.
It seems like
Ecto tests need to run
async: false, but I noticed this post:
@benwilson512 mentions the use of the
:caller option being passed to
Ecto.Repo functions. However, that post is from 2019, and I don’t see mention of a
:caller option anywhere in the
Can anyone shed light on this?