Skip to content

Commit 16aedf7

Browse files
committed
fix: Flush pool as late as possible during schema cache reloading
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 b9e24c5 commit 16aedf7

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
@@ -371,8 +371,6 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
371371
observer $ ConnectionRetryObs delay
372372
putNextListenerDelay appState delay
373373

374-
flushPool appState
375-
376374
(,) <$> qPgVersion <*> (qInDbConfig *> qSchemaCache)
377375
)
378376
where
@@ -421,6 +419,10 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
421419
-- 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.
422420
putSCacheStatus appState SCPending
423421
putSchemaCache appState $ Just sCache
422+
-- Flush the pool after loading the schema cache to reset any stale session cache entries
423+
-- We do it after successfully querying the schema cache
424+
-- and after marking sCacheStatus as pending,
425+
flushPool appState
424426
observer $ SchemaCacheQueriedObs resultTime
425427
(t, _) <- timeItT $ observer $ SchemaCacheSummaryObs $ showSummary sCache
426428
observer $ SchemaCacheLoadedObs t

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
@@ -49,22 +49,21 @@ spec = describe "Server started with metrics enabled" $ do
4949
waitFor (1 * sec) "SchemaCacheLoadedObs" $ \x -> [ o | o@SchemaCacheLoadedObs{} <- pure x ]
5050

5151

52-
it "Should flush pool multiple times when schema reloading retries" $ do
52+
it "Should flush pool once when schema reloading retries" $ do
5353
(appState, waitFor) <- prepareState
5454

5555
liftIO $ do
5656
AppState.getConfig appState >>= \cfg -> do
5757
AppState.putConfig appState $ cfg { configDbSchemas = pure "bad_schema" }
5858
AppState.schemaCacheLoader appState
5959

60-
waitFor (1 * sec) "PoolFlushed 1" $ \x -> [ o | o@PoolFlushed <- pure x ]
6160
waitFor (1 * sec) "SchemaCacheErrorObs" $ \x -> [ o | o@SchemaCacheErrorObs{} <- pure x ]
6261

6362
-- Restore configuration
6463
AppState.putConfig appState cfg
6564

6665
-- Wait for 2 seconds so that retry can happen
67-
waitFor (2 * sec) "PoolFlushed 2" $ \x -> [ o | o@PoolFlushed <- pure x ]
66+
waitFor (2 * sec) "PoolFlushed" $ \x -> [ o | o@PoolFlushed <- pure x ]
6867
waitFor (1 * sec) "SchemaCacheQueriedObs" $ \x -> [ o | o@SchemaCacheQueriedObs{} <- pure x ]
6968
waitFor (1 * sec) "SchemaCacheLoadedObs" $ \x -> [ o | o@SchemaCacheLoadedObs{} <- pure x ]
7069

0 commit comments

Comments
 (0)