on master help sign in
Add an optional graceful shutdown timeout

For servers with long-lived (or infinite lived) connections, waiting for graceful shutdown can block the server indefinitely. A new setting is added, which allows for a time (in seconds) to be applied when commencing a graceful shutdown.

commitaebd8d4081297a31726bcfeb947d525bfd816437 authorReid Draper <reiddraper@gmail.com> dateWed 18 May 2016, 14:11 (10 years ago) parent31d0012
3 files changed+27−3
warp/Network/Wai/Handler/Warp.hs+13 warp/Network/Wai/Handler/Warp/Run.hs+10−3 warp/Network/Wai/Handler/Warp/Settings.hs+4
warp/Network/Wai/Handler/Warp.hs+13
@@ -70,12 +70,14 @@ module Network.Wai.Handler.Warp (
7070 , setSlowlorisSize
7171 , setHTTP2Disabled
7272 , setLogger
73+ , setGracefulShutdownTimeout
7374 -- ** Getters
7475 , getPort
7576 , getHost
7677 , getOnOpen
7778 , getOnClose
7879 , getOnException
80+ , getGracefulShutdownTimeout
7981 -- ** Exception handler
8082 , defaultOnException
8183 , defaultShouldDisplayException
@@ -244,6 +246,10 @@ getOnClose = settingsOnClose
244246getOnException :: Settings -> Maybe Request -> SomeException -> IO ()
245247getOnException = settingsOnException
246248
249+-- | Get the graceful shutdown timeout
250+getGracefulShutdownTimeout :: Settings -> Maybe Int
251+getGracefulShutdownTimeout = settingsGracefulShutdownTimeout
252+
247253-- | A code to install shutdown handler.
248254--
249255-- For instance, this code should set up a UNIX signal
@@ -347,6 +353,13 @@ setLogger :: (Request -> H.Status -> Maybe Integer -> IO ())
347353 -> Settings -> Settings
348354setLogger lgr y = y { settingsLogger = lgr }
349355
356+-- | Set the graceful shutdown timeout. A timeout of `Nothing' will
357+-- wait indefinitely, and a number, if provided, will be treated as seconds
358+-- to wait for requests to finish, before shutting down the server entirely.
359+setGracefulShutdownTimeout :: Maybe Int
360+ -> Settings -> Settings
361+setGracefulShutdownTimeout time y = y { settingsGracefulShutdownTimeout = time }
362+
350363-- | Explicitly pause the slowloris timeout.
351364--
352365-- This is useful for cases where you partially consume a request body. For
warp/Network/Wai/Handler/Warp/Run.hs+10−3
@@ -45,6 +45,7 @@ import qualified Network.Wai.Handler.Warp.Timeout as T
4545import Network.Wai.Handler.Warp.Types
4646import Network.Wai.Internal (ResponseReceived (ResponseReceived))
4747import System.Environment (getEnvironment)
48+import System.Timeout (timeout)
4849
4950#if WINDOWS
5051import Network.Wai.Handler.Warp.Windows
@@ -218,7 +219,7 @@ acceptConnection set getConnMaker app counter ii0 = do
218219 -- ensure that no async exception is throw between the call to
219220 -- acceptNewConnection and the registering of connClose.
220221 void $ mask_ acceptLoop
221− gracefulShutdown counter
222+ gracefulShutdown set counter
222223 where
223224 acceptLoop = do
224225 -- Allow async exceptions before receiving the next connection maker.
@@ -495,5 +496,11 @@ setSocketCloseOnExec _ = return ()
495496setSocketCloseOnExec socket = F.setFileCloseOnExec $ fromIntegral $ fdSocket socket
496497#endif
497498
498−gracefulShutdown :: Counter -> IO ()
499−gracefulShutdown counter = waitForZero counter
499+gracefulShutdown :: Settings -> Counter -> IO ()
500+gracefulShutdown set counter =
501+ case settingsGracefulShutdownTimeout set of
502+ Nothing ->
503+ waitForZero counter
504+ (Just seconds) ->
505+ void (timeout (seconds * microsPerSecond) (waitForZero counter))
506+ where microsPerSecond = 1000000
warp/Network/Wai/Handler/Warp/Settings.hs+4
@@ -101,6 +101,9 @@ data Settings = Settings
101101 -- ^ A log function. Default: no action.
102102 --
103103 -- Since 3.X.X.
104+ , settingsGracefulShutdownTimeout :: Maybe Int
105+ -- ^ An optional timeout to limit the time (in seconds) waiting for
106+ -- a graceful shutdown of the web server.
104107 }
105108
106109-- | Specify usage of the PROXY protocol.
@@ -135,6 +138,7 @@ defaultSettings = Settings
135138 , settingsSlowlorisSize = 2048
136139 , settingsHTTP2Enabled = True
137140 , settingsLogger = \_ _ _ -> return ()
141+ , settingsGracefulShutdownTimeout = Nothing
138142 }
139143
140144-- | Apply the logic provided by 'defaultOnException' to determine if an