Skip to content

Commit c9846f6

Browse files
authored
fix: Remove refresh_publiation API form PubMan (#3168)
Fixes #3167 We started seeing this error with an update made on 22nd of September, and until then one of the relevant changes included is this: #3108 Since @alco has introduced periodic forced publication updates anyway, and upon reconciling the schema we also trigger dropping relevant shapes (which would remove them from the publication on cleanup), we no longer need to refresh the publication manually IMO - not much to be gained other than unnecessary dependencies between our processes. It's still worth investigating why we're seeing these timeouts (but was harder to debug because we were missing sentry metadata, see #3166) - but ultimately we should simplify things. 1. Schema gets reconciled 2. Shapes using diverged/stale relations get dropped 3. Shape cleanup will involve removing them from the publication which should cause a publication update (as all relevant shapes for a given relation will be removed) 4. Even if (3) doesn't occur, which it will, we now periodically refresh the publication anyway In fact, I would go even further to say that since we're periodically refreshing the publication and thus detecting missing relations there, we should simply add an inspector cleanup and get rid of the schema reconciler in its entirety - what do you think @alco @icehaunter ?
1 parent 5ca7997 commit c9846f6

9 files changed

Lines changed: 13 additions & 120 deletions

File tree

‎.changeset/little-seals-try.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@core/sync-service": patch
3+
---
4+
5+
Remove unncecessary `refresh_publication` API from `PublicationManager`.

‎integration-tests/tests/not-owner-of-the-table.lux‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,8 @@
6969
[shell electric]
7070
??[info] Configuring publication electric_publication_integration to drop ["public.items"] tables, and add [] tables
7171

72-
# Call refresh_publication() once more to ensure the previous update has completed. This is
73-
# going to be a noop call since there are no changes pending for the publication.
74-
!Electric.Replication.PublicationManager.refresh_publication(stack_id: "single_stack", forced?: true)
75-
??:ok
72+
# sleep a bit to ensure the publication update completed
73+
[sleep 3]
7674

7775
[shell psql]
7876
!SELECT * FROM pg_publication_tables;

‎packages/sync-service/lib/electric/replication/publication_manager.ex‎

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ defmodule Electric.Replication.PublicationManager do
1414
@callback name(binary() | Keyword.t()) :: term()
1515
@callback add_shape(shape_handle(), Shape.t(), Keyword.t()) :: :ok
1616
@callback remove_shape(shape_handle(), Keyword.t()) :: :ok
17-
@callback refresh_publication(Keyword.t()) :: :ok
1817

1918
defstruct [
2019
:stack_id,
@@ -117,21 +116,6 @@ defmodule Electric.Replication.PublicationManager do
117116
end
118117
end
119118

120-
@impl __MODULE__
121-
def refresh_publication(opts \\ []) do
122-
server = Access.get(opts, :server, name(opts))
123-
timeout = Access.get(opts, :timeout, 10_000)
124-
125-
case GenServer.call(
126-
server,
127-
{:refresh_publication, Access.get(opts, :forced?, false)},
128-
timeout
129-
) do
130-
:ok -> :ok
131-
{:error, err} -> raise err
132-
end
133-
end
134-
135119
def start_link(opts) do
136120
with {:ok, opts} <- NimbleOptions.validate(opts, @schema) do
137121
stack_id = Keyword.fetch!(opts, :stack_id)
@@ -201,16 +185,6 @@ defmodule Electric.Replication.PublicationManager do
201185
end
202186
end
203187

204-
def handle_call({:refresh_publication, forced?}, from, state) do
205-
if forced? or update_needed?(state) do
206-
state = add_waiter(from, state)
207-
state = schedule_update_publication(state.update_debounce_timeout, forced?, state)
208-
{:noreply, state}
209-
else
210-
{:reply, :ok, state, state.publication_refresh_period}
211-
end
212-
end
213-
214188
defguardp is_fatal(err)
215189
when is_exception(err, Postgrex.Error) and
216190
err.postgres.code in ~w|undefined_function undefined_table insufficient_privilege|a

‎packages/sync-service/lib/electric/replication/schema_reconciler.ex‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ defmodule Electric.Replication.SchemaReconciler do
1313
require Logger
1414

1515
alias Electric.Postgres.Inspector
16-
alias Electric.Replication.PublicationManager
1716
alias Electric.ShapeCache.ShapeCleaner
1817

1918
@name_schema_tuple {:tuple, [:atom, :atom, :any]}
2019
@genserver_name_schema {:or, [:atom, @name_schema_tuple]}
21-
@addressable_process {:or, [:atom, :pid, @name_schema_tuple]}
2220
@schema NimbleOptions.new!(
2321
name: [type: @genserver_name_schema, required: false],
2422
period: [type: :pos_integer, required: false, default: 60_000],
2523
inspector: [type: :any, required: true],
26-
stack_id: [type: :string, required: true],
27-
publication_manager: [type: @addressable_process, required: false]
24+
stack_id: [type: :string, required: true]
2825
)
2926

3027
def start_link(opts) do
@@ -92,10 +89,7 @@ defmodule Electric.Replication.SchemaReconciler do
9289
with :ok <-
9390
ShapeCleaner.remove_shapes_for_relations(diverged_relations, stack_id: state.stack_id),
9491
:ok <-
95-
Enum.each(diverged_relations, fn {oid, _} ->
96-
Inspector.clean(oid, state.inspector)
97-
end),
98-
:ok <- PublicationManager.refresh_publication(stack_id: state.stack_id, forced?: true) do
92+
Enum.each(diverged_relations, fn {oid, _} -> Inspector.clean(oid, state.inspector) end) do
9993
:ok
10094
else
10195
{:error, reason} ->

‎packages/sync-service/test/electric/replication/publication_manager_db_test.exs‎

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -83,30 +83,5 @@ defmodule Electric.Replication.PublicationManagerDbTest do
8383
end
8484
end
8585

86-
describe "refresh_publication()" do
87-
setup ctx do
88-
shape = generate_shape(ctx.relation_with_oid)
89-
:ok = PublicationManager.add_shape(@shape_handle_1, shape, ctx.pub_mgr_opts)
90-
end
91-
92-
test "updates the publication if a published table is dropped", ctx do
93-
Postgrex.query!(ctx.pool, "DROP TABLE items")
94-
95-
assert :ok == PublicationManager.refresh_publication(ctx.pub_mgr_opts ++ [forced?: true])
96-
assert [] == fetch_pub_tables(ctx)
97-
98-
assert_receive {:remove_shapes_for_relations, [{_oid, {"public", "items"}}]}
99-
end
100-
101-
test "updates the publication if a published table is renamed", ctx do
102-
Postgrex.query!(ctx.pool, "ALTER TABLE items RENAME TO items_no_more")
103-
104-
assert :ok == PublicationManager.refresh_publication(ctx.pub_mgr_opts ++ [forced?: true])
105-
assert [] == fetch_pub_tables(ctx)
106-
107-
assert_receive {:remove_shapes_for_relations, [{_oid, {"public", "items"}}]}
108-
end
109-
end
110-
11186
defp fetch_pub_tables(ctx), do: fetch_publication_tables(ctx.pool, ctx.publication_name)
11287
end

‎packages/sync-service/test/electric/replication/publication_manager_manual_test.exs‎

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,4 @@ defmodule Electric.Replication.PublicationManagerManualTest do
8484
assert_receive {:remove_shapes_for_relations, [{_oid, {"public", "items"}}]}
8585
end
8686
end
87-
88-
describe "refresh_publication" do
89-
setup ctx do
90-
Postgrex.query!(ctx.pool, "ALTER TABLE items REPLICA IDENTITY FULL")
91-
Postgrex.query!(ctx.pool, "ALTER PUBLICATION #{ctx.publication_name} ADD TABLE items")
92-
93-
shape = generate_shape(ctx.relation_with_oid)
94-
:ok = PublicationManager.add_shape(@shape_handle, shape, ctx.pub_mgr_opts)
95-
end
96-
97-
test "verifies publication state when a table is dropped and cleans up the corresponding shape",
98-
ctx do
99-
Postgrex.query!(ctx.pool, "DROP TABLE items")
100-
101-
assert :ok == PublicationManager.refresh_publication(ctx.pub_mgr_opts ++ [forced?: true])
102-
103-
assert_receive {:remove_shapes_for_relations, [{_oid, {"public", "items"}}]}
104-
end
105-
106-
test "verifies publication state when a table is renamed and cleans up the corresponding shape",
107-
ctx do
108-
Postgrex.query!(ctx.pool, "ALTER TABLE items RENAME TO items_no_more")
109-
110-
assert :ok == PublicationManager.refresh_publication(ctx.pub_mgr_opts ++ [forced?: true])
111-
112-
assert_receive {:remove_shapes_for_relations, [{_oid, {"public", "items"}}]}
113-
end
114-
end
11587
end

‎packages/sync-service/test/electric/replication/publication_manager_test.exs‎

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,32 +65,15 @@ defmodule Electric.Replication.PublicationManagerTest do
6565
refute_receive {:filters, _}, 200
6666
end
6767

68-
@tag update_debounce_timeout: 10
6968
test "accepts multiple relations", %{opts: opts} do
7069
shape1 = generate_shape({"public", "items"})
7170
shape2 = generate_shape({"public", "other"})
71+
7272
assert :ok == PublicationManager.add_shape(@shape_handle_1, shape1, opts)
73-
assert :ok == PublicationManager.add_shape(@shape_handle_2, shape2, opts)
73+
assert_receive {:filters, [{_, {"public", "items"}}]}, 500
7474

75-
collected =
76-
receive do
77-
{:filters, filters} -> MapSet.new(filters)
78-
after
79-
500 -> flunk("Did not receive initial filters")
80-
end
81-
82-
# Force refresh to ensure any pending prepared filters are committed
83-
:ok = PublicationManager.refresh_publication(Keyword.merge(opts, forced?: true))
84-
85-
collected =
86-
receive do
87-
{:filters, filters} ->
88-
MapSet.union(collected, MapSet.new(filters))
89-
after
90-
200 -> collected
91-
end
92-
93-
assert [{_, {"public", "items"}}, {_, {"public", "other"}}] = MapSet.to_list(collected)
75+
assert :ok == PublicationManager.add_shape(@shape_handle_2, shape2, opts)
76+
assert_receive {:filters, [{_, {"public", "items"}}, {_, {"public", "other"}}]}, 500
9477
end
9578

9679
@tag update_debounce_timeout: 100

‎packages/sync-service/test/electric/shape_cache/expiry_manager_test.exs‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ defmodule Electric.ExpiryManagerTest do
3838
def add_shape(_handle, _, opts) do
3939
send(opts[:test_pid], {:called, :prepare_tables_fn})
4040
end
41-
42-
def refresh_publication(_), do: :ok
4341
end
4442

4543
setup :verify_on_exit!

‎packages/sync-service/test/support/component_setup.ex‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ defmodule Support.ComponentSetup do
1515
def name(_), do: :pub_man
1616
def add_shape(_handle, _shape, _opts), do: :ok
1717
def remove_shape(_handle, _opts), do: :ok
18-
def refresh_publication(_opts), do: :ok
1918
end
2019

2120
defmodule TestPublicationManager do
@@ -36,11 +35,6 @@ defmodule Support.ComponentSetup do
3635
send(parent, {TestPublicationManager, :remove_shape, handle})
3736
:ok
3837
end
39-
40-
def refresh_publication(%{parent: parent}) do
41-
send(parent, {TestPublicationManager, :refresh_publication})
42-
:ok
43-
end
4438
end
4539

4640
def with_stack_id_from_test(ctx) do

0 commit comments

Comments
 (0)