如何在WAI服务器中实现shutdown命令?

时间:2011-10-24 20:07:54

标签: haskell yesod

我想为我的webapp实现'graceful shutdown'命令(而不是我的第一直觉,就是要求人们杀死进程)

我的前两次尝试包括

  1. liftIO exitSuccess
  2. E.yield (responseLBS statusOK [G.contentType "text/plain"] "") E.EOF
  3. 两者都只是愉快地将结果返回给客户并继续收听。应用程序可以做什么来杀死服务器?这甚至是一件合理的事情吗?

    我承认我对iteratee没有很强的理解,只知道我可以消耗我的输入并且Iteratee是一个MonadIO实例。

1 个答案:

答案 0 :(得分:11)

  1. 使用MVar。阻止主线程直到MVar发出信号,然后清理并退出。
  2. 致电exitImmediately。拆除过程的最快方法之一,也非常讨厌调试。我不相信终结者/括号/最后一个块会在下降的过程中被调用,具体取决于你的应用程序它可能会破坏状态。
  3. 向主线程抛出异常。 Warp.run不会捕获异常,因此这可以通过允许主线程(以及仅主线程)上的默认异常处理程序来终止进程。
  4. 正如其他人所说,使用MVar可能是最好的选择。为了完整起见,我把其他人包括在内,但他们确实有自己的位置。 throwTo在基础库中有点使用,我使用了一些使用等效于exitImmediatelyexit()的C的应用程序,虽然我没有遇到任何Haskell应用程序使用这种方法。

    {-# LANGUAGE DeriveDataTypeable #-}
    {-# LANGUAGE OverloadedStrings #-}
    
    module Main (main) where
    
    import Control.Concurrent (MVar, ThreadId, forkIO, myThreadId, newEmptyMVar, putMVar, takeMVar)
    import Control.Exception (Exception, throwTo)
    import Control.Monad.Trans (liftIO)
    import Data.ByteString (ByteString)
    import Data.Data (Data, Typeable)
    import Data.Enumerator (Iteratee)
    import Network.HTTP.Types
    import Network.Wai as Wai
    import Network.Wai.Handler.Warp as Warp
    import System.Exit (ExitCode (ExitSuccess))
    import System.Posix.Process (exitImmediately)
    
    data Shutdown = Shutdown deriving (Data, Typeable, Show)
    instance Exception Shutdown
    
    app :: ThreadId -> MVar () -> Request -> Iteratee ByteString IO Response
    app mainThread shutdownMVar Request{pathInfo = pathInfo} = do
      liftIO $ case pathInfo of
        ["shutdownByThrowing"] -> throwTo mainThread Shutdown
        ["shutdownByMVar"]     -> putMVar shutdownMVar ()
        ["shutdownByExit"]     -> exitImmediately ExitSuccess
        _                      -> return ()
      return $ responseLBS statusOK [headerContentType "text/plain"] "ok"
    
    main :: IO ()
    main = do
      mainThread <- myThreadId
      shutdownMVar <- newEmptyMVar
      forkIO $ Warp.run 3000 (app mainThread shutdownMVar)
      takeMVar shutdownMVar