2012-08-30 2 views
2

HTTP 클라이언트가 연결을 끊을 때 클린업하는 방법을 알아낼 수 없거나 다른 실제 세계이 발생합니다. 내 SourceaddCleanup에 넣으려고했으나 전화를받지 못했습니다.WAI/Warp ResponseSource 정리

여기 bytestrings 스트리밍 infinte 자료 내 최소한의 예입니다 : 내가 HTTP 요청과 충돌

{-# LANGUAGE OverloadedStrings #-} 

module Main where 

import Network.Wai 
import Network.HTTP.Types 
import Network.Wai.Handler.Warp (run) 
import Data.ByteString.Lazy.Char8() 

import Control.Monad 
import Control.Monad.Trans 
import Control.Concurrent (threadDelay) 

import Data.Conduit 
import Blaze.ByteString.Builder (Builder) 
import qualified Blaze.ByteString.Builder.ByteString as BBBB 
import qualified Data.ByteString.Char8 as BS 

stream :: Source (ResourceT IO) (Flush Builder) 
stream = addCleanup (\_ -> liftIO $ putStrLn "cleanup.") $ do 
    liftIO $ putStrLn "source started." 
    yield Flush 

    forever $ do 
     yield $ bchunk "whatever" 
     yield Flush 
     liftIO $ threadDelay 10000 

app :: Application 
app req = do 
    liftIO $ putStrLn "in the handler." 
    return $ ResponseSource status200 [("Content-Type", "text/plain")] stream 

main :: IO() 
main = run 3000 app 

bchunk = Chunk . BBBB.fromByteString . BS.pack 

는 "시작"주의 사항은 표시하고 stream 데이터를 puring 시작합니다. 그러나 연결을 닫은 후에는 "정리"를 수행 할 수 없습니다. 메시지가 나타나고 아무 작업도 수행되지 않아 실제 코드에서 리소스가 누출됩니다.

답변

3

내가 선호하는 정리 방법은 Control.Monad.Trans.Resource.MonadResource에 정의 된 allocate 또는 register 함수를 사용하는 것입니다. 이것은 ResponseSource이 종료 될 때 호출되는 처리기를 가져 오거나 예외를 발생시킵니다.

코드는 addCleanup이며, 일반 (비 예외적) 완료에만 사용됩니다.

{-# LANGUAGE OverloadedStrings #-} 

module Main where 

import Network.Wai 
import Network.HTTP.Types 
import Network.Wai.Handler.Warp (run) 
import Data.ByteString.Lazy.Char8() 

import Control.Monad 
import Control.Monad.Trans 
import Control.Monad.Trans.Resource 
import Control.Concurrent (threadDelay) 

import Data.Conduit 
import Blaze.ByteString.Builder (Builder) 
import qualified Blaze.ByteString.Builder.ByteString as BBBB 
import qualified Data.ByteString.Char8 as BS 

stream :: MonadResource m => Source m (Flush Builder) 
stream = do 
    -- the release key can be used for early cleanup 
    _releaseKey <- lift . register $ putStrLn "cleanup." 

    liftIO $ putStrLn "source started." 
    yield Flush 

    forever $ do 
    yield $ bchunk "whatever" 
    yield Flush 
    liftIO $ threadDelay 10000 

app :: Application 
app _ = do 
    liftIO $ putStrLn "in the handler." 
    return $ ResponseSource status200 [("Content-Type", "text/plain")] stream 

main :: IO() 
main = run 3000 app 

bchunk :: String -> Flush Builder 
bchunk = Chunk . BBBB.fromByteString . BS.pack