mbaeuerle

mbaeuerle

Ecto test multiple process transaction in sandbox with shared connection

I basically have a similar setup like the one described in the sandbox docs for a shared mode connection, which looks like this:

setup do
  :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
  Ecto.Adapters.SQL.Sandbox.mode(Repo, {:shared, self()})
end

test "create two posts, one sync, another async" do
  task = Task.async(fn ->
    Repo.insert!(%Post{title: "async"})
  end)
  assert %Post{} = Repo.insert!(%Post{title: "sync"})
  assert %Post{} = Task.await(task)
end

Which runs fine.
Now when I change this example slightly and wrap both inserts in a transaction:

test "create two posts, one sync, another async" do
  Repo.transaction(fn ->
    task = Task.async(fn ->
      Repo.insert!(%Post{title: "async"})
    end)
    assert %Post{} = Repo.insert!(%Post{title: "sync"})
    assert %Post{} = Task.await(task)
  end)
end

This leads to a timeout:

 ** (EXIT from #PID<0.478.0>) exited in: GenServer.call(#PID<0.479.0>, {:checkout, #Reference<0.0.3.2012>, true, 15000}, 5000)
     ** (EXIT) time out

.10:04:12.191 [error] Postgrex.Protocol (#PID<0.383.0>) disconnected: ** (DBConnection.ConnectionError) owner #PID<0.478.0> exited while client #PID<0.478.0> is still running with: exited in: GenServer.call(#PID<0.479.0>, {:checkout, #Reference<0.0.3.2012>, true, 15000}, 5000)
** (EXIT) time out

I am wondering if this is because I can’t use transactions with the shared mode or if I am missing something else. I am using PostgreSQL 9.6.2, Ecto 2.1.4 and Elixir 1.4.2

Marked As Solved

michalmuskala

michalmuskala

The answer is that Ecto transactions, in general, can’t span multiple processes.

Also Liked

hubertlepicki

hubertlepicki

You probably want to test the spawned functions separately in that case. But you can create nested transactions form the same process, this should not be the issue at all. As long as you stay within the same process you should have no issues.

For the cases you have to spawn processes that do database operations, I would go with combination of async: false in your test cases, and switching to shared mode: Ecto.Adapters.SQL.Sandbox – Ecto v2.2.8

The end result should be that these tests will not run in parallel with other tests, so possibly would be slower than doing it in parallel, but there is nothing stopping you from havihng some tests running in parallel, and others not.

al2o3cr

al2o3cr

You can definitely do both things with Ecto.Adapters.SQL.Sandbox, but depending on exactly how the process is spawned you may need to manually ensure the connection gets shared using Ecto.Adapters.SQL.Sandbox.allow.

IIRC, on Elixir 1.8+ the original poster’s use of a Task spawned from the test process will automatically share the DB connection.

Last Post!

ndan

ndan

Ecto solves it by avoiding asynchronous preloading when a connection is checked out (inside test or transaction)

    Repo.transaction(fn ->
      task =
        if Repo.checked_out?() do
          Task.completed(%Post{title: "async"})
        else
          Task.async(fn ->
            %Post{title: "async"}
          end)
        end

      assert %Post{} = Repo.insert!(%Post{title: "sync"})
      assert %Post{} = Task.await(task)
    end)

Thanks to arnodirlam

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement