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, _}
- 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?