From c5c9dc33c99dfb3d0381ea29c043e55da76f1405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C5=82eczek?= Date: Sun, 28 Jun 2026 08:11:35 +0200 Subject: [PATCH] refactor: make sure proper sockets cleanup is performed in App.run Right now code in App.run does not properly use bracket/finally to close sockets and clean-up mainSocketRef. This is not a big problem at the moment because the application is going to exit enyway but introducting proper resource handling will make future refactorings safer. --- src/PostgREST/App.hs | 48 ++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index 5ea9179d4..10a62d5b0 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -24,7 +24,6 @@ import GHC.IO.Exception (IOErrorType (..)) import System.IO.Error (ioeGetErrorType) import Control.Monad.Except (liftEither) -import Control.Monad.Extra (whenJust) import Data.Either.Combinators (mapLeft, whenLeft) import Data.IORef (atomicWriteIORef, newIORef, readIORef) @@ -83,39 +82,44 @@ run appState = do conf <- AppState.getConfig appState mainSocketRef <- newIORef Nothing - adminSocket <- initAdminServerSocket conf + let setMainSocketRef = atomicWriteIORef mainSocketRef . Just + clearMainSocketRef = atomicWriteIORef mainSocketRef Nothing - let closeSockets = do - whenJust adminSocket NS.close - readIORef mainSocketRef >>= foldMap NS.close - Unix.installSignalHandlers observer closeSockets (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState) + bracket (initAdminServerSocket conf) ensureSocketClosed $ \adminSocket -> do - Admin.runAdmin appState adminSocket (checkMainAppLive (readIORef mainSocketRef)) (serverSettings conf) + let closeSockets = do + ensureSocketClosed adminSocket + ensureSocketClosed =<< readIORef mainSocketRef + Unix.installSignalHandlers observer closeSockets (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState) - Listener.runListener appState + Admin.runAdmin appState adminSocket (checkMainAppLive (readIORef mainSocketRef)) (serverSettings conf) - -- Kick off and wait for the initial SchemaCache load before creating the - -- main API socket. - AppState.schemaCacheLoader appState - AppState.waitForSchemaCacheInit appState + Listener.runListener appState - mainSocket <- initServerSocket conf - atomicWriteIORef mainSocketRef $ Just mainSocket + -- Kick off and wait for the initial SchemaCache load before creating the + -- main API socket. + AppState.schemaCacheLoader appState + AppState.waitForSchemaCacheInit appState - let app = postgrest appState (AppState.schemaCacheLoader appState) + bracket (initServerSocket conf) NS.close $ \mainSocket -> do - address <- resolveSocketToAddress mainSocket + let app = postgrest appState (AppState.schemaCacheLoader appState) - let - appServerSettings = serverSettings conf - & setPort (configServerPort conf) - & setOnException onWarpException - & setBeforeMainLoop (observer $ AppServerAddressObs address) + address <- resolveSocketToAddress mainSocket - Warp.runSettingsSocket appServerSettings mainSocket app + let + appServerSettings = serverSettings conf + & setPort (configServerPort conf) + & setOnException onWarpException + & setBeforeMainLoop (setMainSocketRef mainSocket *> observer (AppServerAddressObs address)) + + Warp.runSettingsSocket appServerSettings mainSocket app + `finally` clearMainSocketRef where observer = AppState.getObserver appState + ensureSocketClosed = foldMap NS.close + onWarpException :: Maybe Wai.Request -> SomeException -> IO () onWarpException _ ex = when (shouldDisplayException ex) $