18

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

我的前两次尝试包括

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

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

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

4

1 回答 1

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

正如其他人所提到的,使用 MVar 可能是最好的选择。为了完整起见,我包括了其他人,但他们确实有自己的位置。throwTo在基本库中使用了一些,我已经开发了一些使用 C 等效的exitImmediately:的应用程序exit(),尽管我没有运行过任何使用这种方法的 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 
于 2011-11-17T05:59:33.697 回答