如何在WAI服务器中实现关机命令? [英] How do I implement a shutdown command in a WAI server?

查看:114
本文介绍了如何在WAI服务器中实现关机命令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为我的webapp执行'graceful shutdown'命令(而不是我的第一本能,就是要求人们杀死这个进程)。

我的前两次尝试包括:


  1. liftIO exitSuccess

  2. E.yield(responseLBS statusOK [G.contentTypetext / plain])E.EOF

两者都乐意将结果返回给客户端并继续收听。有什么应用程序可以做到杀死服务器?这是一个合理的想要做的事情吗?



我承认我对iteratee没有很强的理解,只知道我可以使用我的输入而且Iteratee是MonadIO实例。

解决方案


  1. 使用MVar。阻塞主线程,直到MVar发出信号,然后清理并退出。

  2. 调用 exitImmediately 。最快的方式之一,以及调试过程中非常烦人的方法。我不相信finalizers / brackets / finally块会被调用,取决于您的应用程序它可能会破坏状态。

  3. 向主线程抛出异常。 Warp.run 不会捕获异常,因此这可以通过允许主线程(仅主线程)上的默认异常处理程序来终止进程。

正如其他人所说,使用MVar可能是最好的选择。为了完整起见,我包括了其他人,但他们确实有自己的位置。 throwTo 在基础库中有所用处,我已经使用了一些使用C的等价物 exitImmediately exit(),尽管我没有运行任何使用此方法的Haskell应用程序。

  { - #LANGUAGE DeriveDataTypeable# - } 
{ - #LANGUAGE OverloadedStrings# - }

模块Main(main)其中

import Control.Concurrent(MVar,ThreadId,forkIO,myThreadId,newEmptyMVar,putMVar,takeMVar)
导入Control.Exception(Exception,throwTo)
导入Control.Monad.Trans(liftIO)
导入数据.ByteString(ByteString)
导入Data.Data(Data,Typeable)
导入Data.Enumerator(Iteratee)
导入Network.HTTP.Types
导入Network.Wai作为Wai
导入Network.Wai.Handler.Warp作为Warp
导入System.Exit(ExitCode(ExitSuccess))
导入System.Posix.Process(exitImmediately)

data关闭=关闭导出(Data,Typeable,Show)
实例Excepti关机

app :: ThreadId - > MVar() - >请求 - > Iteratee ByteString IO Response
app mainThread shutdownMVar Request {pathInfo = pathInfo} = do
liftIO $ case $ b $ pathInfo [shutdownByThrowing] - > throwTo mainThread关闭
[shutdownByMVar] - > putMVar shutdownMVar()
[shutdownByExit] - > exitImmediately ExitSuccess
_ - >返回()
return $ responseLBS statusOK [headerContentTypetext / plain]ok
$ b $ main :: IO()
main = do
mainThread< - myThreadId
shutdownMVar< - newEmptyMVar
forkIO $ Warp.run 3000(app mainThread shutdownMVar)
takeMVar shutdownMVar


I'd like to implement a 'graceful shutdown' command for my webapp (as opposed to my first instinct, which is to just ask people to kill the process)

My first two attempts consisted of

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

Both of which just cheerfully returned a result to the client and continued listening. Is there anything an application can do to kill the server? Is this even a reasonable thing to want to do?

I confess I don't have a very strong understanding of iteratee, only enough to know that I can consume my input and that Iteratee is a MonadIO instance.

解决方案

  1. Use an MVar. Block the main thread until the MVar has been signaled, then cleanup and exit.
  2. Call exitImmediately. One of the fastest ways to tear down the process, and also terribly annoying to debug. I don't believe finalizers/brackets/finally blocks will be called on the way down, depending on your application it may corrupt state.
  3. Throw an exception to the main thread. Warp.run doesn't catch exceptions, so this works by allowing the default exception handler on the main thread (and the main thread only) to terminate the process.

As others have mentioned, using an MVar is probably the best option. I included the others for the sake of completeness, but they do have their place. throwTo is used somewhat in the base library and I've worked on a few applications that use the C equivalent of exitImmediately: exit(), though I haven't run across any Haskell apps that use this method.

{-# 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 

这篇关于如何在WAI服务器中实现关机命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆