haskell - programar - ¿Cómo implemento un comando de apagado en un servidor WAI?
programar encendido y apagado ubuntu (1)
- Utilice un MVar. Bloquee el hilo principal hasta que la MVar haya sido señalizada, luego limpie y salga.
- Llamar a la
exitImmediately
. Una de las maneras más rápidas de demorar el proceso, y también terriblemente molesta de depurar. No creo que los finalizadores / paréntesis / finalmente los bloques se llamen en el camino hacia abajo, dependiendo de su aplicación, puede dañar el estado. - Lanzar una excepción al hilo principal.
Warp.run
noWarp.run
excepciones, por lo que esto funciona al permitir que el controlador de excepciones predeterminado en el subproceso principal (y solo el subproceso principal) finalice el proceso.
Como han mencionado otros, usar una MVar es probablemente la mejor opción. Incluí a los otros por el bien de la integridad, pero tienen su lugar. throwTo
se usa de alguna manera en la biblioteca base y he trabajado en algunas aplicaciones que usan el equivalente en C de exitImmediately
: exit()
, aunque no he encontrado ninguna aplicación de Haskell que use este método.
{-# 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
Me gustaría implementar un comando de ''cierre elegante'' para mi aplicación web (en oposición a mi primer instinto, que es simplemente pedirle a la gente que mate el proceso)
Mis dos primeros intentos consistieron en
liftIO exitSuccess
-
E.yield (responseLBS statusOK [G.contentType "text/plain"] "") E.EOF
Ambos de los cuales simplemente devolvieron alegremente un resultado al cliente y continuaron escuchando. ¿Hay algo que una aplicación pueda hacer para matar el servidor? ¿Es esto incluso algo razonable para querer hacer?
Confieso que no tengo una comprensión muy sólida de iteración, solo lo suficiente para saber que puedo consumir mi entrada y que Iteratee es una instancia de MonadIO.