2011-10-24 25 views
17

Tôi muốn thực hiện một lệnh 'shutdown duyên dáng' cho webapp của tôi (như trái ngược với bản năng đầu tiên của tôi, đó là chỉ cần yêu cầu mọi người giết chết quá trình)Làm cách nào để triển khai lệnh tắt trong máy chủ WAI?

hai nỗ lực đầu tiên của tôi bao gồm

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

Cả hai trong số đó chỉ vui vẻ trở lại một kết quả cho khách hàng và tiếp tục lắng nghe. Có bất cứ điều gì một ứng dụng có thể làm gì để giết máy chủ không? Đây có phải là điều hợp lý để muốn làm không?

Tôi thú nhận rằng tôi không hiểu rõ về iteratee, chỉ đủ để biết rằng tôi có thể tiêu thụ dữ liệu nhập của tôi và Iteratee là một cá thể MonadIO.

+2

Nheo mắt nhìn https://groups.google.com/forum/#!topic/yesodweb/VoenrabRUBQ, một trick mà * dường như * làm việc cho tôi là sử dụng đồng thời Haskell: (1) ngã ba chạy ứng dụng (2) chờ đợi trên một MVar và (3) khi tôi đã sẵn sàng để dừng lại, chỉ cần đặt một cái gì đó vào đó MVar ... – kowey

+2

Đó là những gì tôi muốn giới thiệu là tốt. –

Trả lời

11
  1. Sử dụng MVar. Chặn luồng chính cho đến khi MVar được báo hiệu, sau đó dọn dẹp và thoát.
  2. Gọi exitImmediately. Một trong những cách nhanh nhất để phá bỏ quy trình và cũng gây khó chịu khủng khiếp để gỡ lỗi. Tôi không tin rằng finalizers/brackets/cuối cùng các khối sẽ được gọi trên đường xuống, tùy thuộc vào ứng dụng của bạn nó có thể bị hỏng trạng thái.
  3. Ném ngoại lệ cho chuỗi chính. Warp.run không bắt ngoại lệ, do đó, điều này hoạt động bằng cách cho phép trình xử lý ngoại lệ mặc định trên chuỗi chính (và chỉ chuỗi chính) để chấm dứt quá trình.

Như những người khác đã đề cập, việc sử dụng MVar có lẽ là lựa chọn tốt nhất. Tôi bao gồm những người khác vì lợi ích của sự hoàn chỉnh, nhưng họ có vị trí của họ. throwTo được sử dụng một phần trong thư viện cơ sở và tôi đã làm việc trên một vài ứng dụng sử dụng C tương đương exitImmediately: exit(), mặc dù tôi chưa chạy trên bất kỳ ứng dụng Haskell nào sử dụng phương pháp này.

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

Cảm ơn bạn đã bao quát tất cả các khả năng. Tôi đồng ý rằng tính toàn diện là hữu ích, nếu không có gì khác, để có được một ý tưởng tốt hơn về cách Warp hoạt động. Tôi đã kết thúc tham gia các tuyến đường shutdownByMVar, do đó, sẽ chấp nhận câu trả lời của bạn – kowey

+0

Hm .. Tôi đã thử rằng cách tiếp cận MVar và máy chủ thực sự dừng lại. Tuy nhiên, việc tắt máy không phải là "duyên dáng" - những yêu cầu còn lại đã bị giết chết. – wiz

+1

@wiz Có, nó thoát ngay lập tức. Việc triển khai tắt máy duyên dáng không liên quan nhiều hơn, tôi đã tải lên mẫu * chưa được thử nghiệm tại đây: https://gist.github.com/NathanHowell/5435345 –

Các vấn đề liên quan