fix: not logging termination unix signals

Under container environments like ECS, it's hard to know when PostgREST
is being terminated.
This commit is contained in:
steve-chavez
2026-03-20 13:09:10 -05:00
committed by Steve Chavez
parent 12ef63370b
commit 622c6d3f19
6 changed files with 36 additions and 11 deletions
+4
View File
@@ -15,6 +15,10 @@ All notable changes to this project will be documented in this file. From versio
- Add config `client_error_verbosity` to customize error verbosity by @taimoorzaeem in #4088, #3980, #3824 - Add config `client_error_verbosity` to customize error verbosity by @taimoorzaeem in #4088, #3980, #3824
- Add `Vary` header to responses by @develop7 in #4609 - Add `Vary` header to responses by @develop7 in #4609
### Fixed
- Fix not logging SIGTERM and SIGINT by @steve-chavez in #4728
### Changed ### Changed
- All responses now include a `Vary` header by @develop7 in #4609 - All responses now include a `Vary` header by @develop7 in #4609
+1 -2
View File
@@ -80,7 +80,7 @@ run appState = do
AppState.schemaCacheLoader appState -- Loads the initial SchemaCache AppState.schemaCacheLoader appState -- Loads the initial SchemaCache
(mainSocket, adminSocket) <- initSockets conf (mainSocket, adminSocket) <- initSockets conf
Unix.installSignalHandlers (AppState.getMainThreadId appState) (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState) Unix.installSignalHandlers observer (AppState.getMainThreadId appState) (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState)
Listener.runListener appState Listener.runListener appState
@@ -283,4 +283,3 @@ initSockets AppConfig{..} = do
Nothing -> pure Nothing Nothing -> pure Nothing
pure (sock, adminSock) pure (sock, adminSock)
+2
View File
@@ -228,6 +228,8 @@ observationMessages = \case
pure "Looked up a JWT in JWT cache" pure "Looked up a JWT in JWT cache"
JwtCacheEviction -> JwtCacheEviction ->
pure "Evicted entry from JWT cache" pure "Evicted entry from JWT cache"
TerminationUnixSignalObs signal ->
pure $ "Received termination unix signal " <> signal
WarpErrorObs txt -> WarpErrorObs txt ->
pure $ "Warp server error: " <> txt pure $ "Warp server error: " <> txt
where where
+1
View File
@@ -54,6 +54,7 @@ data Observation
| PoolRequestFullfilled | PoolRequestFullfilled
| JwtCacheLookup Bool | JwtCacheLookup Bool
| JwtCacheEviction | JwtCacheEviction
| TerminationUnixSignalObs Text
| WarpErrorObs Text | WarpErrorObs Text
data ObsFatalError = ServerAuthError | ServerPgrstBug | ServerError42P05 | ServerError08P01 data ObsFatalError = ServerAuthError | ServerPgrstBug | ServerError42P05 | ServerError08P01
+10 -9
View File
@@ -11,26 +11,27 @@ import qualified System.Posix.Signals as Signals
import System.Posix.Types (FileMode) import System.Posix.Types (FileMode)
import System.PosixCompat.Files (setFileMode) import System.PosixCompat.Files (setFileMode)
import Data.String (String) import Data.String (String)
import qualified Network.Socket as NS import qualified Network.Socket as NS
import qualified PostgREST.Observation as Observation
import Protolude import Protolude
import System.Directory (removeFile) import System.Directory (removeFile)
import System.IO.Error (isDoesNotExistError) import System.IO.Error (isDoesNotExistError)
-- | Set signal handlers, only for systems with signals -- | Set signal handlers, only for systems with signals
installSignalHandlers :: ThreadId -> IO () -> IO () -> IO () installSignalHandlers :: Observation.ObservationHandler -> ThreadId -> IO () -> IO () -> IO ()
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
installSignalHandlers tid usr1 usr2 = do installSignalHandlers observer tid usr1 usr2 = do
let interrupt = throwTo tid UserInterrupt let interrupt = throwTo tid UserInterrupt
install Signals.sigINT interrupt install Signals.sigINT $ observer (Observation.TerminationUnixSignalObs "SIGINT") >> interrupt
install Signals.sigTERM interrupt install Signals.sigTERM $ observer (Observation.TerminationUnixSignalObs "SIGTERM") >> interrupt
install Signals.sigUSR1 usr1 install Signals.sigUSR1 usr1
install Signals.sigUSR2 usr2 install Signals.sigUSR2 usr2
where where
install signal handler = install signal handler =
void $ Signals.installHandler signal (Signals.Catch handler) Nothing void $ Signals.installHandler signal (Signals.Catch handler) Nothing
#else #else
installSignalHandlers _ _ _ = pass installSignalHandlers _ _ _ _ = pass
#endif #endif
-- | Create a unix domain socket and bind it to the given path. -- | Create a unix domain socket and bind it to the given path.
+18
View File
@@ -127,6 +127,24 @@ def test_graceful_shutdown_waits_for_in_flight_request(defaultenv):
t.join() t.join()
def test_termination_unix_signal_logging(defaultenv):
"Server logs when handling termination unix signals."
with run(env=defaultenv) as postgrest:
postgrest.process.send_signal(signal.SIGTERM)
lines = postgrest.read_stdout(nlines=1)
wait_until_exit(postgrest)
assert any("SIGTERM" in line for line in lines)
with run(env=defaultenv) as postgrest:
postgrest.process.send_signal(signal.SIGINT)
lines = postgrest.read_stdout(nlines=1)
wait_until_exit(postgrest)
assert any("SIGINT" in line for line in lines)
def test_random_port_bound(defaultenv): def test_random_port_bound(defaultenv):
"PostgREST should bind to a random port when PGRST_SERVER_PORT is 0." "PostgREST should bind to a random port when PGRST_SERVER_PORT is 0."