Skip to content

Commit d5b6b67

Browse files
committed
fix: Admin server dies silently
This is a workaround for Warp crashing with "thread blocked indefinitely in an STM transaction" when receiving eMFILE from accept. The fix is to provide Warp with a custom accept function that handles eMFILE by logging it and keeping accepting connections.
1 parent 69d21a8 commit d5b6b67

1 file changed

Lines changed: 20 additions & 4 deletions

File tree

src/PostgREST/Admin.hs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@ module PostgREST.Admin
22
( runAdmin
33
) where
44

5+
import Control.Exception (ExceptionWithContext (ExceptionWithContext),
6+
catchNoPropagate,
7+
rethrowIO)
8+
import Control.Monad.Extra (whenJust)
59
import qualified Data.Aeson as JSON
10+
import Foreign.C.Error (Errno (..), eMFILE)
11+
import GHC.IO.Exception
612
import qualified Network.HTTP.Types.Status as HTTP
13+
import Network.Socket hiding (addrFamily)
14+
import Network.Socket.ByteString
715
import qualified Network.Wai as Wai
816
import qualified Network.Wai.Handler.Warp as Warp
917

10-
import Control.Monad.Extra (whenJust)
11-
import Network.Socket hiding (addrFamily)
12-
import Network.Socket.ByteString
13-
1418
import PostgREST.AppState (AppState, getConfig)
1519
import PostgREST.Config (AppConfig (..))
1620
import PostgREST.MediaType (MediaType (..), toContentType)
@@ -35,9 +39,21 @@ runAdmin appState maybeAdminSocket getSocketREST settings = do
3539
observer = AppState.getObserver appState
3640
adminServerSettings config addr=
3741
settings
42+
& Warp.setAccept safeAccept
3843
& Warp.setBeforeMainLoop (observer $ AdminStartObs addr)
3944
& maybe identity Warp.setPort (configAdminServerPort config)
4045

46+
isEMFILE = (Just eMFILE ==) . fmap Errno . ioe_errno
47+
safeAccept sock =
48+
accept sock `catchNoPropagate`
49+
\ec@(ExceptionWithContext _ e) ->
50+
if isEMFILE e then
51+
-- Keep accepting on eMFILE
52+
-- TODO log observation???
53+
safeAccept sock
54+
else
55+
rethrowIO ec
56+
4157
onError adminSock ex = do
4258
observer $ AdminServerCrashedObs ex
4359
NS.close adminSock -- we close the socket so request doesn't hang

0 commit comments

Comments
 (0)