2011-10-24 15 views
17

me gustaría implementar un comando de 'un apagado' para mi aplicación web (en comparación con mi primer instinto, que es simplemente pedir a la gente para matar el proceso)¿Cómo implemento un comando de apagado en un servidor WAI?

Mis primeros dos intentos consistieron en

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

Ambos de los cuales solo alegremente devuelto un resultado al cliente y continuó escuchando. ¿Hay algo que una aplicación pueda hacer para matar el servidor? ¿Es esto algo razonable que quieras hacer?

Confieso que no tengo una comprensión muy sólida de iteratee, solo lo suficiente como para saber que puedo consumir mi entrada y que Iteratee es una instancia de MonadIO.

+2

Bizqueando en https://groups.google.com/forum/#!topic/yesodweb/VoenrabRUBQ, un truco que parece * * a trabajar para mí es el uso concurrente de Haskell: (1) la ejecución de la horquilla aplicación (2) espere en un MVar y (3) cuando esté listo para detenerse, simplemente ponga algo en ese MVar ... – kowey

+2

Eso es lo que yo recomendaría también. –

Respuesta

11
  1. Utilice un MVar. Bloquee el hilo principal hasta que se haya señalizado el MVar, luego limpie y salga.
  2. Llamada exitImmediately. Una de las maneras más rápidas de derribar el proceso, y también terriblemente molesto para depurar. No creo que los finalizadores/corchetes/bloques finalmente se llamarán en el camino hacia abajo, dependiendo de su aplicación puede corromper el estado.
  3. Lanza una excepción al hilo principal. Warp.run no capta excepciones, por lo que esto funciona al permitir que el manejador de excepciones predeterminado en el hilo principal (y solo el hilo principal) finalice el proceso.

Como han mencionado otros, usar un MVar es probablemente la mejor opción. Incluí los otros para completar, pero tienen su lugar. throwTo se usa algo 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 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 
+0

Gracias por cubrir todas las posibilidades. Estoy de acuerdo en que la comprensión es útil, por lo menos, para tener una mejor idea de cómo funciona Warp. Terminé tomando la ruta shutdownByMVar, así que aceptaré tu respuesta – kowey

+0

Hm .. He intentado con ese enfoque MVar y el servidor se detiene. Sin embargo, el cierre no fue "elegante" - las solicitudes restantes fueron eliminadas. – wiz

+1

@wiz Sí, sale inmediatamente. Implementar un cierre elegante no es mucho más complicado, he subido una muestra * no probada * aquí: https://gist.github.com/NathanHowell/5435345 –

Cuestiones relacionadas