2011-10-24 26 views
17

WAI sunucusunda kapatma komutunu nasıl uygularım?

Benim ilk iki girişimleri

    oluşuyordu (sadece süreci öldürmek için insanlara sormaktır benim ilk içgüdüsü, aksine) Benim webapp için bir 'zarif kapatma' komutunu uygulamak istiyorum
  1. liftIO exitSuccess
  2. E.yield (responseLBS statusOK [G.contentType "text/plain"] "") E.EOF

İkisi arasında sadece neşeyle istemciye bir sonuç döndü ve dinleme devam etti. Bir uygulamayı sunucuyu öldürmek için yapabileceği bir şey var mı? Bu yapmak istediğin makul bir şey mi?

İtiraf ediyorum, yalnızca benim girişimi tüketebileceğimi ve yinelemenin bir MonadIO örneği olduğunu bilmem için yeterince güçlü bir yineleme anlayışım yok.

+2

, * * benim için çalışmak Eşzamanlı Haskell kullanmaktır görünüyor bir hile: (1) çalıştırmak çatal Uygulama (2) bir MVar üzerinde beklemek ve (3) durdurmak için hazır olduğumda, sadece bir şey o MVar içine koymak ... – kowey

+2

Ben de bunu tavsiye ederim. –

cevap

11
  1. MVar kullanın. MVar işaret edilene kadar ana ipliği bloke edin, sonra temizleyin ve çıkın.
  2. exitImmediately numaralı telefonu arayın. Süreci yırtmak için en hızlı yollardan biri ve aynı zamanda hata ayıklama için can sıkıcı. Uygulamanıza bağlı olarak devletin yol açabileceği son parantezler/parantezler/son olarak bloklar aşağıya ineceğine inanmıyorum.
  3. Ana iş parçacığına bir istisna atın. Warp.run istisnaları yakalamaz, bu nedenle işlemi iptal etmek için ana iş parçacığının (ve yalnızca ana iş parçacığının) varsayılan istisna işleyicisine izin vererek çalışır.

Diğerlerinin de belirttiği gibi, bir MVar kullanmak muhtemelen en iyi seçenektir. Tamlığı sağlamak için diğerlerini de dahil ettim, ama onların yerine sahipler. throwTo, temel kitaplığında biraz kullanılır ve bu yöntemi kullanan herhangi bir Haskell uygulamasında rastlamamış olsa da, C12 exitImmediately: exit() eşdeğerini kullanan birkaç uygulama üzerinde çalıştım. https://groups.google.com/forum/#!topic/yesodweb/VoenrabRUBQ de gözlerini kısarak

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

Tüm olasılıkları karşıladığınız için teşekkür ederiz. Warp'in nasıl çalıştığı konusunda daha iyi bir fikir edinmek için, başka bir şey olmasa da, kapsamlılığın yararlı olduğunu kabul ediyorum. Ben shutdownByMVar rota alarak bitti, bu yüzden cevabınızı kabul edecek – kowey

+0

Hm .. Ben MVar yaklaşımını denedim ve sunucu gerçekten durur. Ancak, kapatma "zarif" değildi - kalan istekler öldürüldü. – wiz

+1

@wiz Evet, hemen çıkar. Zarif bir kapatma uygulamak daha fazla uğraşmıyor, burada * test edilmemiş * bir örnek yükledim: https://gist.github.com/NathanHowell/5435345 –

İlgili konular