【问题标题】:How do I implement a shutdown command in a WAI server?如何在 WAI 服务器中实现关闭命令?
【发布时间】:2011-12-14 10:39:36
【问题描述】:

我想为我的 web 应用程序实现一个“正常关闭”命令(与我的第一直觉相反,即要求人们终止进程)

我的前两次尝试包括

  1. liftIO exitSuccess
  2. E.yield (responseLBS statusOK [G.contentType "text/plain"] "") E.EOF

两者都只是兴高采烈地向客户返回结果并继续收听。应用程序有什么可以杀死服务器的吗?这甚至是一件合理的事情吗?

我承认我对 iteratee 的理解不是很深,只知道我可以使用我的输入并且 Iteratee 是一个 MonadIO 实例。

【问题讨论】:

  • 眯着眼睛看groups.google.com/forum/#!topic/yesodweb/VoenrabRUBQ似乎对我有用的一个技巧是使用 Concurrent Haskell:(1) fork 运行应用程序 (2) 等待一个 MVar 和(3) 当我准备停下来的时候,把东西放进那个 MVar...
  • 这也是我推荐的。

标签: haskell yesod


【解决方案1】:
  1. 使用 MVar。阻塞主线程直到 MVar 发出信号,然后清理并退出。
  2. 致电exitImmediately。拆除流程的最快方法之一,调试起来也非常烦人。我不相信终结器/括号/finally 块会在下降过程中被调用,这取决于您的应用程序,它可能会损坏状态。
  3. 向主线程抛出异常。 Warp.run 不会捕获异常,因此这通过允许主线程(并且仅限主线程)上的默认异常处理程序终止进程来工作。

正如其他人所提到的,使用 MVar 可能是最好的选择。为了完整起见,我包括了其他人,但他们确实有自己的位置。 throwTo 在基础库中使用了一些,我已经开发了一些使用 exitImmediately:exit() 等效的 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 

【讨论】:

  • 感谢您涵盖所有可能性。我同意全面性对于更好地了解 Warp 的工作原理很有用。我最终选择了 shutdownByMVar 路线,所以会接受你的回答
  • 嗯.. 我已经尝试过 MVar 方法,服务器确实停止了。然而,关闭并不是“优雅的”——剩余的请求被终止了。
  • @wiz 是的,它立即退出。实现正常关机并没有更多的涉及,我在这里上传了一个未经测试的示例:gist.github.com/NathanHowell/5435345
  • @wiz 更改它很简单...您的处理程序只需要检查是否正在进行关闭并在这种情况下返回 503。无论如何,我已经再次更新了示例。
  • 我想知道服务器本身是否可以/应该做这样的事情,即停止接受新连接并让其他连接完成......
猜你喜欢
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 2013-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多