trisolaran

trisolaran

Hello!

I noticed that if I have a LV test that uses the Ecto sandbox in manual mode, the LV process in the test has “magically” access to the sandboxed DB connection created by the test process. This is really amazing but I don’t understand how it works :slight_smile:

Simplified example:

Liveview:

defmodule MyAppWeb.LiveView do
  @moduledoc false

  import Ecto.Query

  use MyAppWeb, :live_view

  @impl true
  def mount(_params, _session, socket) do
    connect_params = get_connect_params(socket)

    IO.inspect(connect_params, label: "connect_params")
    IO.inspect(self(), label: "I'm the LV")
    Repo.all(MyApp.User) |> length() |> IO.inspect(label: "users")

    {:ok, socket}
  end
end

Test setup:

defmodule MyAppWeb.ConnCase do
  ...

  setup tags do
    Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :manual)

    :ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)

    {:ok, conn: Phoenix.ConnTest.build_conn()}
  end
end

The actual test:

defmodule MyAppWeb.LiveViewTest do 
    use MyAppWeb.ConnCase

    test "just to prove a point", %{conn: conn} do 
      insert_test_records_in_user_table(20)

      IO.inspect(self(), label: "I'm the test process")

      {:ok, view, html} = live(conn, "/live_view")
   end 
end

Output:

1 I'm the test process: #PID<0.869.0>
2 connect_params: nil
3 I'm the LV: #PID<0.869.0>
4 entries: 20
5 connect_params: %{"_mounts" => 0}
6 I'm the LV: #PID<0.873.0>
7 entries: 20

Lines 2-4 come from the static LV mount, and lines 5-7 from the connected one. As you can see, the static mount happens in the same process as the test’s, while the connected mount happens in a different process. So far nothing strange. What I don’t understand is how the connected LV can see the test records inserted by the test process, even though I didn’t change the mode of the sandbox to shared or call Ecto.Adapters.SQL.Sandbox.allow. I would have expected the DB access from the connected LV process to fail with the error:
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.873.0>

The only explanation I can think of is that the sandboxed DB connection is somehow passed over to the LV process when this latter is spawned, by calling Ecto.Adapters.SQL.Sandbox.allow somewhere. But I couldn’t find where this happens in the code.

Can someone please clarify this for me?

Showing Posts 1 to 6

LostKobrakai

LostKobrakai

The sandbox uses the mechanic described here to track the caller (aka the test process) for a LV: Task — Elixir v1.12.3

With that pid as key it can fetch the connection checked out by that process.

trisolaran

trisolaran OP

Thanks @LostKobrakai! Very interesting. I guess it must be using the mechanism you describe, it’s just that I can’t find where this happens in the code.

trisolaran

trisolaran OP

Thanks. This explains it. So this is a generic mechanism, not specific to LV. Whenever the sandbox can track the caller using the $callers key in the process dictionary, it will try to use a DB connection from the caller, and no explicit allowances are needed. So this works whenever I start a new process using Task, Task.Supervisor, or Supervisor (I just tested with Task.async and it works).

I have to say I was completely in the dark about this one. The sandbox docs never mention it (Ecto.Adapters.SQL.Sandbox — Ecto SQL v3.14.0). I think they should. Reading the docs I would think that you need allowances or shared DB connections whenever you’re dealing with subprocesses, but clearly this is not necessary if you are using supervised tasks and that’s very relevant information.

trisolaran

trisolaran OP

I mean, how did you find about this mechanism @LostKobrakai ? Just poking around in the code, or did you read about it somewhere?

LostKobrakai

LostKobrakai

There we‘re some blogposts around the introduction to the functionality for Tasks, which is by now a lot of elixir versions back. While ecto sandbox piggibacks on this, it‘s afaik meant to be a much more general feature (hence it‘s inclusion in elixir core). But it should probably still be mentioned in the docs that processes supporting $caller keys might get automatic concurrent support with the sandbox.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews