Skip to content

Commit a9f1a00

Browse files
authored
fix: race condition compiling migrations when concurrently creating new tenants (#406)
1 parent c4cc329 commit a9f1a00

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

lib/migration_compile_cache.ex

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
defmodule AshPostgres.MigrationCompileCache do
2+
@moduledoc """
3+
A cache for the compiled migrations.
4+
5+
This is used to avoid recompiling the migration files
6+
every time a migration is run, as well as ensuring that
7+
migrations are compiled sequentially.
8+
9+
This is important because otherwise there is a race condition
10+
where two invocations could be compiling the same migration at
11+
once, which would error out.
12+
"""
13+
14+
def start_link(opts \\ %{}) do
15+
Agent.start_link(fn -> opts end, name: __MODULE__)
16+
end
17+
18+
@doc """
19+
Compile a file, caching the result for future calls.
20+
"""
21+
def compile_file(file) do
22+
Agent.get_and_update(__MODULE__, fn state ->
23+
new_state = ensure_compiled(state, file)
24+
{Map.get(new_state, file), new_state}
25+
end)
26+
end
27+
28+
defp ensure_compiled(state, file) do
29+
case Map.get(state, file) do
30+
nil ->
31+
compiled = Code.compile_file(file)
32+
Map.put(state, file, compiled)
33+
_ ->
34+
state
35+
end
36+
end
37+
38+
end

lib/multitenancy.ex

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ defmodule AshPostgres.MultiTenancy do
6161
end
6262

6363
defp load_migration!({version, _, file}) when is_binary(file) do
64-
loaded_modules = file |> Code.compile_file() |> Enum.map(&elem(&1, 0))
64+
loaded_modules = file |> compile_file() |> Enum.map(&elem(&1, 0))
6565

6666
if mod = Enum.find(loaded_modules, &migration?/1) do
6767
{version, mod}
@@ -70,6 +70,11 @@ defmodule AshPostgres.MultiTenancy do
7070
"file #{Path.relative_to_cwd(file)} does not define an Ecto.Migration"
7171
end
7272
end
73+
74+
defp compile_file(file) do
75+
AshPostgres.MigrationCompileCache.start_link()
76+
AshPostgres.MigrationCompileCache.compile_file(file)
77+
end
7378

7479
defp migration?(mod) do
7580
function_exported?(mod, :__migration__, 0)

0 commit comments

Comments
 (0)