Skip to content

Commit b3f6755

Browse files
committed
pr feedback
1 parent 58bdd19 commit b3f6755

File tree

3 files changed

+48
-34
lines changed

3 files changed

+48
-34
lines changed

packages/sync-service/lib/electric/shape_cache/shape_status/shape_db/connection.ex

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,20 +197,22 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDb.Connection do
197197
end
198198

199199
@impl NimblePool
200-
def handle_ping(%__MODULE__{} = state, pool_state) do
201-
Logger.debug(fn -> ["Closing idle SQLite ", to_string(state.mode), " connection"] end)
202-
200+
def handle_ping(%__MODULE__{} = _conn, _pool_state) do
203201
# the idle timeout is only enabled in non-exclusive mode, so we're free
204202
# to close all the connections, including write.
205-
206-
:ok = close(state)
207-
:ok = Statistics.worker_stop(Keyword.get(pool_state, :stack_id))
208-
209203
{:remove, :idle}
210204
end
211205

212-
def shrink_memory(conn) when is_raw_connection(conn) do
213-
execute(conn, "PRAGMA shrink_memory")
206+
@impl NimblePool
207+
def terminate_worker(reason, conn, pool_state) do
208+
Logger.debug(fn ->
209+
["Closing SQLite ", to_string(conn.mode), " connection for reason: ", inspect(reason)]
210+
end)
211+
212+
_ = close(conn)
213+
:ok = Statistics.worker_stop(Keyword.get(pool_state, :stack_id))
214+
215+
{:ok, pool_state}
214216
end
215217

216218
@max_recovery_attempts 2

packages/sync-service/lib/electric/shape_cache/shape_status/shape_db/statistics.ex

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDb.Statistics do
6161
page_size: 0,
6262
stats: %{},
6363
connections: 0,
64-
use_pool?: Keyword.get(args, :exclusive_mode, false),
64+
first_run?: true,
65+
exclusive_mode?: Keyword.get(args, :exclusive_mode, false),
6566
enable_memory_stats?: enable_memory_stats?,
6667
measurement_period: measurement_period,
6768
pool_opts: args
@@ -115,7 +116,7 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDb.Statistics do
115116
state
116117
|> open_connection(fn conn ->
117118
with {:ok, memstat_available?, page_size} <-
118-
initialize_connection(conn, state.enable_memory_stats?),
119+
initialize_connection(conn, state.first_run?, state.enable_memory_stats?),
119120
{:ok, stats} <-
120121
Connection.fetch_all(
121122
conn,
@@ -130,21 +131,37 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDb.Statistics do
130131
%{state | stats: stats}
131132

132133
{:error, reason} ->
133-
Logger.warning(["Failed to read statistics: ", inspect(reason)])
134+
Logger.warning(["Failed to read SQLite statistics: ", inspect(reason)])
135+
state
136+
137+
:error ->
138+
Logger.warning("Failed to read SQLite statistics")
134139
state
135140
end
141+
|> then(fn
142+
%{first_run?: true} = state ->
143+
%{state | first_run?: false}
144+
145+
state ->
146+
state
147+
end)
136148
|> tap(fn state ->
137149
Process.send_after(self(), :read_stats, state.measurement_period)
138150
end)
139151
end
140152

141-
defp open_connection(%{use_pool?: true} = state, fun) do
153+
# In exclusive_mode we *must* use a pooled connection because the db maybe
154+
# in-memory. This is ok because in this mode we never close the single
155+
# connection instance so using it won't prevent closing idle connections.
156+
defp open_connection(%{exclusive_mode?: true} = state, fun) do
142157
Connection.checkout_write!(state.stack_id, :read_stats, fn %{conn: conn} ->
143158
fun.(conn)
144159
end)
145160
end
146161

147-
defp open_connection(%{use_pool?: false, pool_opts: pool_opts} = _state, fun) do
162+
# read the stats over a completely new connection to avoid waking a pool
163+
# worker and preventing it from reaching the idle timeout
164+
defp open_connection(%{exclusive_mode?: false, pool_opts: pool_opts} = _state, fun) do
148165
with {:ok, conn} <- Connection.open(pool_opts) do
149166
try do
150167
fun.(conn)
@@ -154,11 +171,12 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDb.Statistics do
154171
end
155172
end
156173

157-
defp initialize_connection(conn, enable_memory_stats?) do
174+
defp initialize_connection(conn, first_run?, enable_memory_stats?) do
158175
memstat_available? =
159176
if enable_memory_stats? do
160177
case Connection.enable_extension(conn, "memstat") do
161178
:ok ->
179+
if first_run?, do: Logger.info("SQLite memory statistics enabled")
162180
true
163181

164182
{:error, reason} ->

packages/sync-service/test/electric/shape_cache/shape_status/shape_db_test.exs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -611,15 +611,13 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDbTest do
611611
end
612612

613613
describe "pool scaling" do
614-
@tag shape_db_opts: [connection_idle_timeout: 10, statistics_collection_period: 10]
614+
@tag shape_db_opts: [connection_idle_timeout: 5, statistics_collection_period: 5]
615615
test "scales to 0 if nothing is active", ctx do
616616
ShapeDb.Connection.checkout!(ctx.stack_id, :test, fn _conn ->
617-
Process.sleep(1)
618-
{:ok, %{connections: n}} = ShapeDb.statistics(ctx.stack_id)
619-
assert n == 1
617+
assert :ok = assert_stats_match(ctx, connections: 1)
620618
end)
621619

622-
assert :ok = assert_zero_memory(ctx)
620+
assert :ok = assert_stats_match(ctx, connections: 0, total_memory: 0)
623621
end
624622

625623
@tag shape_db_opts: [
@@ -629,30 +627,26 @@ defmodule Electric.ShapeCache.ShapeStatus.ShapeDbTest do
629627
]
630628
test "does not scale the pool in exclusive mode", ctx do
631629
ShapeDb.Connection.checkout!(ctx.stack_id, :test, fn _conn ->
632-
Process.sleep(1)
633-
{:ok, %{connections: n}} = ShapeDb.statistics(ctx.stack_id)
634-
assert n == 1
630+
assert :ok = assert_stats_match(ctx, connections: 1)
635631
end)
636632

637-
:error = assert_zero_memory(ctx)
633+
assert :error = assert_stats_match(ctx, connections: 0, total_memory: 0)
638634
end
639635

640-
defp assert_zero_memory(ctx, repeats \\ 10)
636+
defp assert_stats_match(ctx, match, repeats \\ 10)
641637

642-
defp assert_zero_memory(_ctx, 0) do
638+
defp assert_stats_match(_ctx, _match, 0) do
643639
:error
644640
end
645641

646-
defp assert_zero_memory(ctx, repeats) do
642+
defp assert_stats_match(ctx, match, repeats) do
647643
{:ok, stats} = ShapeDb.statistics(ctx.stack_id)
648644

649-
case stats do
650-
%{connections: 0, total_memory: 0} ->
651-
:ok
652-
653-
_ ->
654-
Process.sleep(10)
655-
assert_zero_memory(ctx, repeats - 1)
645+
if Enum.all?(match, fn {k, v} -> stats[k] == v end) do
646+
:ok
647+
else
648+
Process.sleep(10)
649+
assert_stats_match(ctx, match, repeats - 1)
656650
end
657651
end
658652
end

0 commit comments

Comments
 (0)