[Haskell-cafe] Cloud Haskell real usage example

Thiago Negri evohunz at gmail.com
Wed Aug 22 02:01:30 CEST 2012

Hello everyone. I'm taking my first steps in Cloud Haskell and got
some unexpected behaviors.

I used the code from Raspberry Pi in a Haskell Cloud [1] as a first
example. Did try to switch the code to use Template Haskell with no
luck, stick with the verbose style.
I changed some of the code, from ProcessId-based messaging to typed
channel to receive the Pong; using "startSlave" to start the worker
nodes; and changed the master node to loop forever sending pings to
the worker nodes.

The unexpected behaviors:
- Dropping a worker node while the master is running makes the master
node to crash.
- Master node do not see worker nodes started after the master process.

In order to fix this, I tried to "findSlaves" at the start of the
master process and send ping to only these ones, ignoring the list of
NodeId enforced by the type signature of "startMaster".

Now the master finds new slaves. The bad thing is that when I close
one of the workers, the master process freezes. It simply stop doing
anything. No more messages and no more Pings to other slaves. :(

My view of Cloud Haskell usage would be something similar to this: a
master node sending work to slaves; slave instances getting up or down
based on demand. So, the master node should be slave-failure-proof and
also find new slaves somehow.

Am I misunderstanding the big picture of Cloud Haskell or doing
anything wrong in the following code?

Code (skipped imports and wiring stuff):

newtype Ping = Ping (SendPort Pong)
        deriving (Typeable, Binary, Show)

newtype Pong = Pong ProcessId
        deriving (Typeable, Binary, Show)

worker :: Ping -> Process ()
worker (Ping sPong) = do
  wId <- getSelfPid
  say "Got a Ping!"
  sendChan sPong (Pong wId)

master :: Backend -> [NodeId] -> Process ()
master backend _ = forever $ do
  workers <- findSlaves backend
  say $ "Slaves: " ++ show workers

  (sPong, rPong) <- newChan

  forM_ workers $ \w -> do
    say $ "Sending a Ping to " ++ (show w) ++ "..."
    spawn w (workerClosure (Ping sPong))

  say $ "Waiting for reply from " ++ (show (length workers)) ++ " worker(s)"

  replicateM_ (length workers) $ do
      (Pong wId) <- receiveChan rPong
      say $ "Got back a Pong from " ++ (show $ processNodeId wId) ++ "!"

  (liftIO . threadDelay) 2000000 -- Wait a bit before return

main = do
  prog <- getProgName
  args <- getArgs

  case args of
    ["master", host, port] -> do
      backend <- initializeBackend host port remoteTable
      startMaster backend (master backend)

    ["worker", host, port] -> do
      backend <- initializeBackend host port remoteTable
      startSlave backend

    _ ->
      putStrLn $ "usage: " ++ prog ++ " (master | worker) host port"

[1] http://alenribic.com/writings/post/raspberry-pi-in-a-haskell-cloud

More information about the Haskell-Cafe mailing list