Skip to content

Commit 3e7308f

Browse files
committed
fix: Flush pool as late as possible during schema cache reloading
DISCLAIMER: This commit was authored entirely by a human without the assistance of LLMs. retryingSchemaCacheLoad flushes the pool upon every retry before it starts reloading the schema. This is too early as schema reloading might take some time during which new connections might be acquired. The consequence is that: * upon successful schema cache reload we might have some connections created with the old schema cache * we close connections upon each retry and under load we will keep closing and re-opening connections until schema cache load succeeds This change is to make sure we flush the pool only after successful schema cache querying but before loading (so that connections acquired during loading wait for it and do not interfere with timing the loading process).
1 parent 279ae2d commit 3e7308f

3 files changed

Lines changed: 10 additions & 9 deletions

File tree

src/PostgREST/AppState.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,6 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
370370
let delay = fromMaybe 0 rsPreviousDelay `div` oneSecondInUs
371371
observer $ ConnectionRetryObs delay
372372

373-
flushPool appState
374-
375373
(,) <$> qPgVersion <*> (qInDbConfig *> qSchemaCache)
376374
)
377375
where
@@ -420,6 +418,10 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
420418
-- IORef on putSchemaCache. This is why SCacheStatus is put at SCPending here to signal the Admin server (using isPending) that we're on a recovery state.
421419
putSCacheStatus appState SCPending
422420
putSchemaCache appState $ Just sCache
421+
-- Flush the pool after loading the schema cache to reset any stale session cache entries
422+
-- We do it after successfully querying the schema cache
423+
-- and after marking sCacheStatus as pending,
424+
flushPool appState
423425
observer $ SchemaCacheQueriedObs resultTime
424426
observer . uncurry SchemaCacheLoadedObs =<< timeItT (evaluate $ showSummary sCache)
425427
putSCacheStatus appState SCLoaded

test/io/test_io.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ def test_log_level(level, defaultenv):
674674
response = postgrest.session.get("/")
675675
assert response.status_code == 200
676676

677-
output = postgrest.read_stdout(nlines=7)
677+
output = postgrest.read_stdout(nlines=9)
678678

679679
if level == "crit":
680680
assert len(output) == 0
@@ -712,7 +712,7 @@ def test_log_level(level, defaultenv):
712712
r'- - postgrest_test_anonymous \[.+\] "GET / HTTP/1.1" 200 \d+ "" "python-requests/.+"',
713713
],
714714
)
715-
assert len(output) == 7
715+
assert len(output) == 9
716716
assert any("Connection" and "is available" in line for line in output)
717717
assert any("Connection" and "is used" in line for line in output)
718718

@@ -1349,7 +1349,7 @@ def test_db_error_logging_to_stderr(level, defaultenv, metapostgrest):
13491349
assert response.status_code == 500
13501350

13511351
# ensure the message appears on the logs
1352-
output = postgrest.read_stdout(nlines=6)
1352+
output = postgrest.read_stdout(nlines=8)
13531353

13541354
if level == "crit":
13551355
assert len(output) == 0
@@ -1566,7 +1566,7 @@ def test_log_pool_req_observation(level, defaultenv):
15661566

15671567
if level == "debug":
15681568
output = postgrest.read_stdout(nlines=7)
1569-
assert len(output) == 6
1569+
assert len(output) == 7
15701570
match_log(output, [pool_req, pool_req_fullfill])
15711571
elif level == "info":
15721572
output = postgrest.read_stdout(nlines=4)

test/spec/Feature/SchemaCacheSpec.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ spec = describe "Server started with metrics enabled" $ do
2727
waitFor (1 * sec) "SchemaCacheLoadedObs" $ \x -> [ o | o@SchemaCacheLoadedObs{} <- pure x ]
2828

2929

30-
it "Should flush pool multiple times when schema reloading retries" $ do
30+
it "Should flush pool once when schema reloading retries" $ do
3131
SpecState{specAppState = appState, specObsChan} <- getState
3232
let waitFor = waitForObs specObsChan
3333

@@ -36,14 +36,13 @@ spec = describe "Server started with metrics enabled" $ do
3636
AppState.putConfig appState $ cfg { configDbSchemas = pure "bad_schema" }
3737
AppState.schemaCacheLoader appState
3838

39-
waitFor (1 * sec) "PoolFlushed 1" $ \x -> [ o | o@PoolFlushed <- pure x ]
4039
waitFor (1 * sec) "SchemaCacheErrorObs" $ \x -> [ o | o@SchemaCacheErrorObs{} <- pure x ]
4140

4241
-- Restore configuration
4342
AppState.putConfig appState cfg
4443

4544
-- Wait for 2 seconds so that retry can happen
46-
waitFor (2 * sec) "PoolFlushed 2" $ \x -> [ o | o@PoolFlushed <- pure x ]
45+
waitFor (2 * sec) "PoolFlushed" $ \x -> [ o | o@PoolFlushed <- pure x ]
4746
waitFor (1 * sec) "SchemaCacheQueriedObs" $ \x -> [ o | o@SchemaCacheQueriedObs{} <- pure x ]
4847
waitFor (1 * sec) "SchemaCacheLoadedObs" $ \x -> [ o | o@SchemaCacheLoadedObs{} <- pure x ]
4948

0 commit comments

Comments
 (0)