- 使用 MVar。阻塞主线程直到 MVar 发出信号,然后清理并退出。
- 打电话
exitImmediately
。拆除该过程的最快方法之一,而且调试起来也非常烦人。我不相信终结器/括号/finally 块会在下降过程中被调用,这取决于您的应用程序,它可能会损坏状态。
- 向主线程抛出异常。
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