ravecat

ravecat

Broken test for multi-tenancy and Triplex

Implement complex logic for multi-tenancy solution: create team → create schema → run migration on new schema. Found a thread and a mention in Triplex documentation and moved the migrations from the transaction. Method look like

  def create_team(attrs \\ %{}) do
    changeset =
      %Team{}
      |> change(%{uid: generate_token(type: :schema)})
      |> Team.changeset(attrs)

    Multi.new()
    |> Multi.insert(:team, changeset)
    |> Multi.run(:schema, fn repo, %{team: team} ->
      Triplex.create_schema(team.uid, repo)
    end)
    |> Repo.transaction()
    |> case do
      {:ok, %{team: team}} ->
        {:ok, _} = Triplex.migrate(team.uid)

        {:ok, team}

      {:error, _, reason, _} ->
        {:error, reason}
    end
  end

It work flawless inside iex

iex(97)> Runa.Teams.create_team(%{title: “test”})
[debug] QUERY OK db=0.4ms idle=1327.3ms
begin
↳ Runa.Teams.create_team/1, at: lib/domains/teams/teams.ex:82
[debug] QUERY OK source=“teams” db=0.5ms
INSERT INTO “teams” (“title”,“uid”,“inserted_at”,“updated_at”) VALUES ($1,$2,$3,$4) RETURNING “id” [“test”, “nm8qnu26poykd2y02e0dup5wnf168qz2”, ~U[2024-05-20 17:55:36Z], ~U[2024-05-20 17:55:36Z]]
↳ Runa.Teams.create_team/1, at: lib/domains/teams/teams.ex:82
[debug] QUERY OK db=0.1ms
CREATE SCHEMA “nm8qnu26poykd2y02e0dup5wnf168qz2”
[debug] QUERY OK db=14.5ms
commit
↳ Runa.Teams.create_team/1, at: lib/domains/teams/teams.ex:82
[info] == Running 20240420161100 Runa.Repo.Migrations.CreateContributors.up/0 forward
[info] execute “CREATE TABLE nm8qnu26poykd2y02e0dup5wnf168qz2.contributors (\n id serial PRIMARY KEY,\n user_id integer REFERENCES public.users(id) ON DELETE CASCADE NOT NULL,\n team_id integer REFERENCES public.teams(id) ON DELETE CASCADE NOT NULL,\n role_id integer REFERENCES public.roles(id) ON DELETE CASCADE NOT NULL,\n inserted_at timestamp NOT NULL,\n updated_at timestamp NOT NULL\n);\n”
[info] execute “CREATE UNIQUE INDEX contributors_user_id_team_id_role_id_index\nON nm8qnu26poykd2y02e0dup5wnf168qz2.contributors (user_id, team_id, role_id);\n”
[info] == Migrated 20240420161100 in 0.0s
[info] == Running 20240520093137 Runa.Repo.Migrations.CreateProjectsTable.up/0 forward
[info] create table nm8qnu26poykd2y02e0dup5wnf168qz2.projects
[info] == Migrated 20240520093137 in 0.0s
{:ok,
%Runa.Teams.Team{
meta: #Ecto.Schema.Metadata<:loaded, “teams”>,
id: 53,
title: “test”,
uid: “nm8qnu26poykd2y02e0dup5wnf168qz2”,
team_roles: #Ecto.Association.NotLoaded,
users: #Ecto.Association.NotLoaded,
inserted_at: ~U[2024-05-20 17:55:36Z],
updated_at: ~U[2024-05-20 17:55:36Z]
}}

But inside test in returns error, I use create_project inside the fixture and create a entity, schema and migrations before each test

as I see it migrations cannot be performed in a test environment, but Triplex.exists?(team.uid) return true, Triplex.migrate("public") return {:ok, _}

  1. test projects returns all projects (Runa.ProjectsTest)
    test/domains/projects_test.exs:16
    ** (MatchError) no match of right hand side value: {:error, “could not checkout the connection owned by pid<0.610.0>. When using the sandbox, connections are shared, so this may imply another process is using a connection. Reason: connection not available and request was dropped from queue after 822ms. You can configure how long requests wait in the queue using :queue_target and :queue_interval. See DBConnection.start_link/2 for more information”}
    stacktrace:
    (runa 0.1.0) lib/domains/teams/teams.ex:71: Runa.Teams.create_team/1
    (runa 0.1.0) test/support/fixtures/teams_fixtures.ex:25: Runa.TeamsFixtures.create_aux_team/1
    Runa.ProjectsTest.__ex_unit_describe_0/1

Is this a Triplex problem or a test environment problem?

First Post!

ashrafhasson

ashrafhasson

Hi @ravecat I’ve stumbled upon this too but not the testing part. I didn’t think this would work in iex (or in a transaction) but then it seems it’s only Triplex.create that cannot run inside of a transaction since Ecto 3 :thinking:

However, running the Triplex.create_schema this way inside a multi transaction means it may leave unclean teams’ schemas should the Triplex.migrate fail later on.
If you use the Triplex.create_schema func argument to wrap the transaction instead, you might be able to avoid that side effect.

Regarding the failure in your test, I wonder whether your fixture is spawning a process that’s not dropping the connection before it’s checked out again by the test process? It would be useful to share your fixture and test code here. Also a total speculation is whether you have multiple of these tests in different modules with async turned on ..

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
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

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
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
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
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
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement