fireproofsocks

fireproofsocks

Cachex fallbacks vs. Ecto Sandbox process ownership

I’m working on an app that uses both Cachex and 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 async: false)

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 Cachex + 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 Ecto docs.

Can anyone shed light on this?

First Post!

ruslandoga

ruslandoga

I think :shared mode actually exists for your exact use case: when you can’t explicitly allow every process to use the checked out repo. The error probably is coming from someplace else. Consider this test case:

defmodule Share.Test do
  use Share.DataCase

  test "repo can be called from async function" do
    test = self()

    spawn(fn ->
      assert Share.Repo.query!("select 1 + 1").rows == [[2]]
      send(test, :done)
    end)

    assert_receive :done
  end
end

It passes even though the spawned process is not explicitely allowed to use the repo.

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
dotdotdotPaul
Okay, I’m having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I’m sure I’...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53690 245
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement