Ответ 1
- Используйте MVar. Блокируйте основной поток до тех пор, пока не будет сигнализирован MVAR, затем очистка и выход.
- Вызов
exitImmediately
. Один из самых быстрых способов снести процесс, а также ужасно раздражает отладки. Я не верю, что финализаторы/скобки/окончательные блоки будут вызваны по пути вниз, в зависимости от вашего приложения оно может испортить состояние. - Выбросить исключение из основного потока.
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