Skip to content

Commit 0367a9c

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 26ce39b commit 0367a9c

3 files changed

Lines changed: 10 additions & 10 deletions

File tree

src/PostgREST/AppState.hs

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

305-
flushPool appState
306-
307305
(,) <$> qPgVersion <*> (qInDbConfig *> qSchemaCache)
308306
)
309307
where
@@ -352,6 +350,10 @@ retryingSchemaCacheLoad appState@AppState{stateObserver=observer, stateMainThrea
352350
-- IORef on putSchemaCache. This is why schema cache status is marked as pending here to signal the Admin server (using isPending) that we're on a recovery state.
353351
markSchemaCachePending appState
354352
putSchemaCache appState $ Just sCache
353+
-- Flush the pool after loading the schema cache to reset any stale session cache entries
354+
-- We do it after successfully querying the schema cache
355+
-- and after marking sCacheStatus as pending,
356+
flushPool appState
355357
observer $ SchemaCacheQueriedObs resultTime
356358
observer . uncurry SchemaCacheLoadedObs =<< timeItT (evaluate $ showSummary sCache)
357359
markSchemaCacheLoaded appState

test/io/test_io.py

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

844-
output = postgrest.read_stdout(nlines=7)
844+
output = postgrest.read_stdout(nlines=9)
845845

846846
if level == "crit":
847847
assert len(output) == 0
@@ -879,7 +879,7 @@ def test_log_level(level, defaultenv):
879879
r'- - postgrest_test_anonymous \[.+\] "GET / HTTP/1.1" 200 \d+ "" "python-requests/.+"',
880880
],
881881
)
882-
assert len(output) == 7
882+
assert len(output) == 9
883883
assert any("Connection" and "is available" in line for line in output)
884884
assert any("Connection" and "is used" in line for line in output)
885885

@@ -1507,7 +1507,7 @@ def test_db_error_logging_to_stderr(level, defaultenv, metapostgrest):
15071507
assert response.status_code == 500
15081508

15091509
# ensure the message appears on the logs
1510-
output = postgrest.read_stdout(nlines=6)
1510+
output = postgrest.read_stdout(nlines=8)
15111511

15121512
if level == "crit":
15131513
assert len(output) == 0
@@ -1724,7 +1724,7 @@ def test_log_pool_req_observation(level, defaultenv):
17241724

17251725
if level == "debug":
17261726
output = postgrest.read_stdout(nlines=7)
1727-
assert len(output) == 6
1727+
assert len(output) == 7
17281728
match_log(output, [pool_req, pool_req_fullfill])
17291729
elif level == "info":
17301730
output = postgrest.read_stdout(nlines=4)

test/observability/Observation/SchemaCacheSpec.hs

Lines changed: 2 additions & 4 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,16 +36,14 @@ 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 ]
49-
5048
where
5149
sec = 1000000

0 commit comments

Comments
 (0)