Here (below) is a short program to shut down warp-3.3.15 based on a `TVar Bool` according to any policy you desire (catching a certain exception, receiving a request to a certain route, or receiving an OS signal). You need to route the TVar into places that you want to be able to initiate graceful shutdown. I believe that warp implements graceful shutdown by preventing new clients from connecting, but I haven't dug too far into its source code. In any case, the
setInstallShutdownHandler documentation indicates that you should also use
setGracefulShutdownTimeout to ensure the server eventually shuts down.
I don't think that it's intended to throw exceptions in the setOnException handler or the setOnExceptionResponse handler. The former seems to be a hook for monitoring/logging and the latter a hook to give your users a less scary error page.
--- --- ---
{-# LANGUAGE OverloadedStrings #-}
import qualified Control.Concurrent.Async as Async
import qualified Control.Concurrent.STM as STM
import qualified Network.HTTP.Types as HTTP
import qualified Network.Wai as Wai
import qualified Network.Wai.Handler.Warp as Warp
app :: STM.TVar Bool -> Wai.Application
app shutdownSignal req respond = do
print ("Request from", Wai.remoteHost req)
case Wai.rawPathInfo req of
"/shutdown" -> do
STM.atomically $ STM.writeTVar shutdownSignal True
respond $ Wai.responseLBS HTTP.ok200 [] "shutting down"
_ -> do
respond $ Wai.responseLBS HTTP.ok200 [] "hello"
-- | Spawn a thread to wait for the shutdown signal and initiate shutdown.
installShutdownHandler :: STM.TVar Bool -> (IO ()) -> IO ()
installShutdownHandler shutdownSignal closeSocket = do
_ <- Async.async $ do
STM.atomically $ STM.check =<< STM.readTVar shutdownSignal
closeSocket
return ()
main :: IO ()
main = do
shutdownSignal <- STM.newTVarIO False
let settings
= Warp.setPort 8080
. Warp.setInstallShutdownHandler (installShutdownHandler shutdownSignal)
. Warp.setGracefulShutdownTimeout (Just 30) -- seconds
$ Warp.defaultSettings
print "warp is starting"
Warp.runSettings settings $ app shutdownSignal
print "warp is done"