add(logs): Include a HINT when the LISTEN channel breaks due to a Postgres bug

The HINT shows a SQL command that solves the issue.
This commit is contained in:
Laurence Isla
2026-01-18 18:47:53 +07:00
committed by GitHub
parent c18727ff43
commit c15e908266
3 changed files with 13 additions and 1 deletions
+1
View File
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. From versio
### Added ### Added
- Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359 - Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359
- Add a `HINT` when the LISTEN channel stops working due to a PostgreSQL bug by @laurenceisla in #4581
## [14.3] - 2026-01-03 ## [14.3] - 2026-01-03
+4 -1
View File
@@ -9,7 +9,8 @@ import qualified Hasql.Connection as SQL
import qualified Hasql.Notifications as SQL import qualified Hasql.Notifications as SQL
import PostgREST.AppState (AppState, getConfig) import PostgREST.AppState (AppState, getConfig)
import PostgREST.Config (AppConfig (..)) import PostgREST.Config (AppConfig (..))
import PostgREST.Observation (Observation (..)) import PostgREST.Observation (Observation (..),
isDbListenerBug)
import PostgREST.Version (prettyVersion) import PostgREST.Version (prettyVersion)
import qualified PostgREST.AppState as AppState import qualified PostgREST.AppState as AppState
@@ -33,6 +34,8 @@ retryingListen appState = do
handleFinally err = do handleFinally err = do
AppState.putIsListenerOn appState False AppState.putIsListenerOn appState False
observer $ DBListenFail dbChannel (Right err) observer $ DBListenFail dbChannel (Right err)
when (isDbListenerBug err) $
observer DBListenBugHint
unless configDbPoolAutomaticRecovery $ unless configDbPoolAutomaticRecovery $
killThread mainThreadId killThread mainThreadId
+8
View File
@@ -12,6 +12,7 @@ module PostgREST.Observation
, observationMessage , observationMessage
, ObservationHandler , ObservationHandler
, showOnSingleLine , showOnSingleLine
, isDbListenerBug
) where ) where
import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Lazy as LBS
@@ -46,6 +47,7 @@ data Observation
| DBListenStart Text | DBListenStart Text
| DBListenFail Text (Either SQL.ConnectionError (Either SomeException ())) | DBListenFail Text (Either SQL.ConnectionError (Either SomeException ()))
| DBListenRetry Int | DBListenRetry Int
| DBListenBugHint -- https://github.com/PostgREST/postgrest/issues/3147
| DBListenerGotSCacheMsg ByteString | DBListenerGotSCacheMsg ByteString
| DBListenerGotConfigMsg ByteString | DBListenerGotConfigMsg ByteString
| QueryObs MainQuery Status | QueryObs MainQuery Status
@@ -114,6 +116,8 @@ observationMessage = \case
either showListenerConnError showListenerException listenErr either showListenerConnError showListenerException listenErr
DBListenRetry delay -> DBListenRetry delay ->
"Retrying listening for database notifications in " <> (show delay::Text) <> " seconds..." "Retrying listening for database notifications in " <> (show delay::Text) <> " seconds..."
DBListenBugHint ->
"HINT: This is likely a bug in the notification queue, try executing the following to solve it: select pg_notification_queue_usage();"
DBListenerGotSCacheMsg channel -> DBListenerGotSCacheMsg channel ->
"Received a schema cache reload message on the " <> show channel <> " channel" "Received a schema cache reload message on the " <> show channel <> " channel"
DBListenerGotConfigMsg channel -> DBListenerGotConfigMsg channel ->
@@ -171,3 +175,7 @@ observationMessage = \case
showOnSingleLine :: Char -> Text -> Text showOnSingleLine :: Char -> Text -> Text
showOnSingleLine split txt = T.intercalate " " $ T.filter (/= split) <$> T.lines txt -- the errors from hasql-notifications come intercalated with "\t\n" showOnSingleLine split txt = T.intercalate " " $ T.filter (/= split) <$> T.lines txt -- the errors from hasql-notifications come intercalated with "\t\n"
isDbListenerBug :: Either SomeException () -> Bool
isDbListenerBug (Left e) = "could not access status of transaction" `T.isInfixOf` show e
isDbListenerBug _ = False