git.iko.soy/distributed-process
on master help sign in
More error handling
commit10fef450295610a8df04433cc52bcd5de13f4b17 authorEdsko de Vries <edsko@edsko.net> dateFri 8 Jun 2012, 15:17 (14 years ago) parent006cad8
2 files changed+65−21
distributed-process/src/Control/Distributed/Process.hs+21−17 distributed-process/tests/TestCH.hs+44−4
distributed-process/src/Control/Distributed/Process.hs+21−17
@@ -423,7 +423,8 @@ handleIncomingMessages node = go [] Map.empty
423423 NT.ConnectionClosed cid ->
424424 go (List.delete cid halfOpenConns) (Map.delete cid openConns)
425425 NT.ErrorEvent _ ->
426− fail "handleIncomingMessages: TODO 3"
426+ -- fail "handleIncomingMessages: TODO 3"
427+ go halfOpenConns openConns
427428 NT.EndPointClosed ->
428429 return ()
429430 NT.ReceivedMulticast _ _ ->
@@ -437,26 +438,26 @@ handleIncomingMessages node = go [] Map.empty
437438--------------------------------------------------------------------------------
438439
439440getConnectionTo :: ProcessId -> Process (Maybe NT.Connection)
440−getConnectionTo pid = do
441+getConnectionTo them = do
441442 ourState <- processState <$> ask
442− mConn <- liftIO $ withMVar ourState $ return . (^. connectionTo pid)
443+ mConn <- liftIO $ withMVar ourState $ return . (^. connectionTo them)
443444 case mConn of
444445 Just conn -> return . Just $ conn
445− Nothing -> createConnectionTo pid
446+ Nothing -> createConnectionTo them
446447
447448createConnectionTo :: ProcessId -> Process (Maybe NT.Connection)
448−createConnectionTo pid = do
449+createConnectionTo them = do
449450 proc <- ask
450451 mConn <- liftIO $ NT.connect (localEndPoint . processNode $ proc)
451− (processAddress pid)
452+ (processAddress them)
452453 NT.ReliableOrdered
453454 NT.defaultConnectHints
454455 case mConn of
455456 Right conn -> do
456457 mConn' <- liftIO $ modifyMVar (processState proc) $ \st ->
457− case st ^. connectionTo pid of
458+ case st ^. connectionTo them of
458459 Just conn' -> return (st, Just conn')
459− Nothing -> return (connectionTo pid ^= Just conn $ st, Nothing)
460+ Nothing -> return (connectionTo them ^= Just conn $ st, Nothing)
460461 case mConn' of
461462 Just conn' -> do
462463 -- Somebody else already created a connection while we weren't looking
@@ -467,27 +468,30 @@ createConnectionTo pid = do
467468 liftIO $ NT.close conn
468469 return . Just $ conn'
469470 Nothing -> do
470− sendBinary pid conn $ lpidToPayload (processLocalId pid)
471+ sendBinary them conn $ lpidToPayload (processLocalId them)
471472 return . Just $ conn
472473 Left _err -> do
473474 -- TODO: should probably pass this error to remoteProcessFailed
474− remoteProcessFailed pid
475+ remoteProcessFailed them
475476 return Nothing
476477
477478sendBinary :: ProcessId -> NT.Connection -> [BSS.ByteString] -> Process ()
478−sendBinary pid conn payload = do
479+sendBinary them conn payload = do
479480 result <- liftIO $ NT.send conn payload
480481 case result of
481482 Right () -> return ()
482− Left err -> do
483− ourState <- processState <$> ask
483+ Left _ ->
484+ {-
485+ -- TODO: put into unreachable state rather than Nothing
486+ -- ourState <- processState <$> ask
484487 liftIO $ modifyMVar_ ourState $
485− return . (connectionTo pid ^= Nothing)
486− liftIO $ throwIO err
488+ return . (connectionTo them ^= Nothing)
489+ -}
490+ remoteProcessFailed them
487491
488492sendMessage :: ProcessId -> NT.Connection -> Message -> Process ()
489−sendMessage pid conn (Message fp enc) =
490− sendBinary pid conn $ encodeFingerprint fp : BSL.toChunks enc
493+sendMessage them conn (Message fp enc) =
494+ sendBinary them conn $ encodeFingerprint fp : BSL.toChunks enc
491495
492496payloadToMessage :: [BSS.ByteString] -> Message
493497payloadToMessage payload = Message fp msg
distributed-process/tests/TestCH.hs+44−4
@@ -3,7 +3,7 @@ module Main where
33import Prelude hiding (catch)
44import Data.Binary (Binary)
55import Data.Typeable (Typeable)
6−import Control.Concurrent (forkIO)
6+import Control.Concurrent (forkIO, threadDelay)
77import Control.Concurrent.MVar ( newEmptyMVar
88 , putMVar
99 , takeMVar
@@ -11,6 +11,7 @@ import Control.Concurrent.MVar ( newEmptyMVar
1111 )
1212import Control.Monad (replicateM_)
1313import Control.Distributed.Process
14+import Control.Monad.IO.Class (liftIO)
1415import qualified Network.Transport as NT (Transport)
1516import Network.Transport.TCP (createTransport, defaultTCPParameters)
1617import TestAuxiliary
@@ -57,7 +58,6 @@ testPing transport = do
5758
5859 putMVar clientDone ()
5960
60−
6161 takeMVar clientDone
6262
6363-- | Set up monitoring, send first message to an unreachable node
@@ -109,11 +109,51 @@ testMonitor2 transport = do
109109
110110 takeMVar done
111111
112+-- The first send succeeds, connection is set up, but then the second send
113+-- fails.
114+--
115+-- TODO: should we specify that we receive exactly one notification per process
116+-- failure?
117+testMonitor3 :: NT.Transport -> IO ()
118+testMonitor3 transport = do
119+ firstSend <- newEmptyMVar
120+ serverAddr <- newEmptyMVar
121+ serverDead <- newEmptyMVar
122+ done <- newEmptyMVar
123+
124+ forkIO $ do
125+ localNode <- newLocalNode transport
126+ -- TODO: what happens when processes terminate?
127+ addr <- forkProcess localNode $ return ()
128+ putMVar serverAddr addr
129+ readMVar firstSend
130+ closeLocalNode localNode
131+ threadDelay 10000 -- Give the TCP layer a chance to actually close the socket
132+ putMVar serverDead ()
133+
134+ forkIO $ do
135+ localNode <- newLocalNode transport
136+ theirAddr <- readMVar serverAddr
137+ runProcess localNode $ do
138+ monitor theirAddr MaMonitor
139+ send theirAddr "Hi"
140+ liftIO $ putMVar firstSend () >> readMVar serverDead
141+ send theirAddr "Ho"
142+ ProcessMonitorException pid SrNoPing <- expect
143+ True <- return $ pid == theirAddr
144+ return ()
145+ putMVar done ()
146+
147+ takeMVar done
148+
149+-- TODO: test/specify normal process termination
150+
112151main :: IO ()
113152main = do
114153 Right transport <- createTransport "127.0.0.1" "8080" defaultTCPParameters
115154 runTests
116− [ ("Ping", testPing transport)
117− , ("Monitor1", testMonitor1 transport)
155+ [ -- ("Ping", testPing transport)
156+ ("Monitor1", testMonitor1 transport)
118157 , ("Monitor2", testMonitor2 transport)
158+ , ("Monitor3", testMonitor3 transport)
119159 ]