Add async exception handling for basic runner.
This commit is contained in:
parent
42abd9b666
commit
eb7405765d
@ -21,6 +21,8 @@ module Yesod.Core.Internal.Run
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import qualified GHC.Conc.Sync as Sync
|
||||||
|
import qualified Control.Exception as EUnsafe
|
||||||
import Yesod.Core.Internal.Response
|
import Yesod.Core.Internal.Response
|
||||||
import Data.ByteString.Builder (toLazyByteString)
|
import Data.ByteString.Builder (toLazyByteString)
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
@ -52,6 +54,24 @@ import Yesod.Core.Internal.Util (getCurrentMaxExpiresRFC1123)
|
|||||||
import Yesod.Routes.Class (Route, renderRoute)
|
import Yesod.Routes.Class (Route, renderRoute)
|
||||||
import Control.DeepSeq (($!!), NFData)
|
import Control.DeepSeq (($!!), NFData)
|
||||||
import UnliftIO.Exception
|
import UnliftIO.Exception
|
||||||
|
import UnliftIO(MonadUnliftIO, withRunInIO)
|
||||||
|
|
||||||
|
-- | like `catch` but doesn't check for async exceptions,
|
||||||
|
-- thereby catching them too.
|
||||||
|
-- This is desirable for letting yesod generate a 500 error page
|
||||||
|
-- rather then warp.
|
||||||
|
--
|
||||||
|
-- Normally this is VERY dubious. you need to rethrow.
|
||||||
|
-- recovrery from async isn't allowed.
|
||||||
|
-- see async section: https://www.fpcomplete.com/blog/2018/04/async-exception-handling-haskell/
|
||||||
|
unsafeAsyncCatch
|
||||||
|
:: (MonadUnliftIO m, Exception e)
|
||||||
|
=> m a -- ^ action
|
||||||
|
-> (e -> m a) -- ^ handler
|
||||||
|
-> m a
|
||||||
|
unsafeAsyncCatch f g = withRunInIO $ \run -> run f `EUnsafe.catch` \e -> do
|
||||||
|
liftIO Sync.disableAllocationLimit -- otherwise it can throw again on rendering the 500 page
|
||||||
|
run (g e)
|
||||||
|
|
||||||
-- | Convert a synchronous exception into an ErrorResponse
|
-- | Convert a synchronous exception into an ErrorResponse
|
||||||
toErrorHandler :: SomeException -> IO ErrorResponse
|
toErrorHandler :: SomeException -> IO ErrorResponse
|
||||||
@ -84,7 +104,7 @@ basicRunHandler rhe handler yreq resState = do
|
|||||||
|
|
||||||
-- Run the handler itself, capturing any runtime exceptions and
|
-- Run the handler itself, capturing any runtime exceptions and
|
||||||
-- converting them into a @HandlerContents@
|
-- converting them into a @HandlerContents@
|
||||||
contents' <- catchAny
|
contents' <- unsafeAsyncCatch
|
||||||
(do
|
(do
|
||||||
res <- unHandlerFor handler (hd istate)
|
res <- unHandlerFor handler (hd istate)
|
||||||
tc <- evaluate (toTypedContent res)
|
tc <- evaluate (toTypedContent res)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user