Skip to content

Commit 8a16e68

Browse files
committed
fix: Add random delay in Listener.cacheReloader
Triggering schema cache reload immediately upon receival of notification by the listener leads to thundering herd problem in PostgREST cluster. This change adds random delay between 0 and 1 seconds between notification retrieval and schema cache reload triggering.
1 parent 99984d3 commit 8a16e68

3 files changed

Lines changed: 11 additions & 3 deletions

File tree

postgrest.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ library
158158
, stm-hamt >= 1.2 && < 2
159159
, focus >= 1.0 && < 2
160160
, some >= 1.0.4.1 && < 2
161+
, MonadRandom >= 0.6.2 && < 0.7
161162
-- -fno-spec-constr may help keep compile time memory use in check,
162163
-- see https://gitlab.haskell.org/ghc/ghc/issues/16017#note_219304
163164
-- -optP-Wno-nonportable-include-path

src/PostgREST/Listener.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import qualified PostgREST.AppState as AppState
1818
import qualified PostgREST.Config as Config
1919

2020
import Control.Arrow ((&&&))
21+
import Control.Monad.Random
2122
import Data.Bitraversable (bisequence)
2223
import Data.Either.Combinators (whenRight)
2324
import qualified Database.PostgreSQL.LibPQ as LibPQ
@@ -102,7 +103,13 @@ retryingListen appState = do
102103
| msg == "reload config" -> observer (DBListenerGotConfigMsg channel) >> AppState.readInDbConfig False appState
103104
| otherwise -> pure () -- Do nothing if anything else than an empty message is sent
104105

105-
cacheReloader =
106+
-- add a random delay between 0 and 1 second to avoid thundering herd problem
107+
-- if multiple listeners receive the same notification at the same time
108+
-- the cacheReloader is launched in a separate thread to avoid blocking the listener
109+
-- during the random delay
110+
cacheReloader = void $ forkIO $ do
111+
delay <- getRandomR (0, 1000000)
112+
threadDelay delay
106113
AppState.schemaCacheLoader appState
107114

108115
releaseConnection = void . forkIO . handle (observer . DBListenerConnectionCleanupFail) . SQL.release

test/io/postgrest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
def sleep_until_postgrest_scache_reload():
2020
"Sleep until schema cache reload"
21-
time.sleep(0.3)
21+
time.sleep(1)
2222

2323

2424
def sleep_until_postgrest_config_reload():
@@ -28,7 +28,7 @@ def sleep_until_postgrest_config_reload():
2828

2929
def sleep_until_postgrest_full_reload():
3030
"Sleep until schema cache plus config reload"
31-
time.sleep(0.3)
31+
time.sleep(1)
3232

3333

3434
class PostgrestTimedOut(Exception):

0 commit comments

Comments
 (0)