static void Main(string[] args) { if (args == null || args.Length == 0) { Console.WriteLine(); Console.WriteLine("Usage: ./{0} PPWorker [Name]", AppDomain.CurrentDomain.FriendlyName); Console.WriteLine(); Console.WriteLine(" Name Your name. Default: World"); Console.WriteLine(); args = new string[] { "World" }; } string name = args[0]; ZError error; using (var context = new ZContext()) { ZSocket worker = null; try // using (worker) { if (null == (worker = PPWorker_CreateZSocket(context, name, out error))) { if (error == ZError.ETERM) { return; // Interrupted } throw new ZException(error); } // If liveness hits zero, queue is considered disconnected int liveness = Worker.PPP_HEARTBEAT_LIVENESS; int interval = Worker.PPP_INTERVAL_INIT; // Send out heartbeats at regular intervals DateTime heartbeat_at = DateTime.UtcNow + Worker.PPP_HEARTBEAT_INTERVAL; ZMessage incoming; int cycles = 0; var poll = ZPollItem.CreateReceiver(); var rnd = new Random(); while (true) { if (worker.PollIn(poll, out incoming, out error, Worker.PPP_TICK)) { // Get message // - 3-part envelope + content -> request // - 1-part HEARTBEAT -> heartbeat using (incoming) { incoming.DumpZmsg("-----------from queue------------"); // To test the robustness of the queue implementation we // simulate various typical problems, such as the worker // crashing or running very slowly. We do this after a few // cycles so that the architecture can get up and running // first: if (incoming.Count >= 3) { Common.ProgramerHelper.Console_WriteZMessage("I: receiving reply", incoming); cycles++; if (cycles > 3 && rnd.Next(5) == 0) { Console.WriteLine("I: simulating a crash"); return; } if (cycles > 3 && rnd.Next(3) == 0) { Console.WriteLine("I: simulating CPU overload"); Thread.Sleep(100); } Thread.Sleep(1); // Do some heavy work Console.WriteLine("I: sending reply"); worker.Send(incoming); liveness = Worker.PPP_HEARTBEAT_LIVENESS; } // When we get a heartbeat message from the queue, it means the // queue was (recently) alive, so we must reset our liveness // indicator: else if (incoming.Count == 1) { string identity = incoming[0].ReadString(); if (identity == Worker.PPP_HEARTBEAT) { Console.WriteLine("I: receiving heartbeat"); liveness = Worker.PPP_HEARTBEAT_LIVENESS; } else { ProgramerHelper.Console_WriteZMessage("E: invalid message", incoming); } } else { ProgramerHelper.Console_WriteZMessage("E: invalid message", incoming); } } interval = Worker.PPP_INTERVAL_INIT; } else { if (error == ZError.ETERM) { break; // Interrupted } if (error != ZError.EAGAIN) { throw new ZException(error); } } if (error == ZError.EAGAIN) { // If the queue hasn't sent us heartbeats in a while, destroy the // socket and reconnect. This is the simplest most brutal way of // discarding any messages we might have sent in the meantime: if (--liveness == 0) { Console.WriteLine("W: heartbeat failure, can't reach queue"); Console.WriteLine("W: reconnecting in {0} ms", interval); Thread.Sleep(interval); if (interval < Worker.PPP_INTERVAL_MAX) { interval *= 2; } else { Console.WriteLine("E: interrupted"); break; } worker.Dispose(); if (null == (worker = PPWorker_CreateZSocket(context, name, out error))) { if (error == ZError.ETERM) { break; // Interrupted } throw new ZException(error); } liveness = Worker.PPP_HEARTBEAT_LIVENESS; } } // Send heartbeat to queue if it's time if (DateTime.UtcNow > heartbeat_at) { heartbeat_at = DateTime.UtcNow + Worker.PPP_HEARTBEAT_INTERVAL; Console.WriteLine("I: sending heartbeat"); using (var outgoing = new ZFrame(Worker.PPP_HEARTBEAT)) { worker.Send(outgoing); } } } } finally { if (worker != null) { worker.Dispose(); worker = null; } } } }
static void Main(string[] args) { using (var context = new ZContext()) using (var backend = new ZSocket(context, ZSocketType.ROUTER)) using (var frontend = new ZSocket(context, ZSocketType.ROUTER)) { backend.Bind("tcp://*:5556"); frontend.Bind("tcp://*:5555"); // List of available workers var workers = new List <Worker>(); // Send out heartbeats at regular intervals DateTime heartbeat_at = DateTime.UtcNow + Worker.PPP_HEARTBEAT_INTERVAL; // Create a Receiver ZPollItem (ZMQ_POLLIN) var poll = ZPollItem.CreateReceiver(); ZError error; ZMessage incoming; while (true) { // Handle worker activity on backend if (backend.PollIn(poll, out incoming, out error, Worker.PPP_TICK)) { using (incoming) { incoming.DumpZmsg("--------from worker---------"); // Any sign of life from worker means it's ready ZFrame identity = incoming.Unwrap(); var worker = new Worker(identity); workers.Ready(worker); // Validate control message, or return reply to client if (incoming.Count == 1) { string message = incoming[0].ReadString(); if (message == Worker.PPP_READY) { Console.WriteLine("I: worker ready ({0})", worker.IdentityString); } else if (message == Worker.PPP_HEARTBEAT) { Console.WriteLine("I: receiving heartbeat ({0})", worker.IdentityString); } else { ProgramerHelper.Console_WriteZMessage("E: invalid message from worker", incoming); } } else { if (ProgramerHelper.Verbose) { ProgramerHelper.Console_WriteZMessage("I: [backend sending to frontend] ({0})", incoming, worker.IdentityString); } frontend.Send(incoming); } } } else { if (error == ZError.ETERM) { break; // Interrupted } if (error != ZError.EAGAIN) { throw new ZException(error); } } // Handle client activity on frontend if (workers.Count > 0) { // Poll frontend only if we have available workers if (frontend.PollIn(poll, out incoming, out error, Worker.PPP_TICK)) { // Now get next client request, route to next worker using (incoming) { ZFrame workerIdentity = workers.Next(); incoming.Prepend(workerIdentity); if (ProgramerHelper.Verbose) { ProgramerHelper.Console_WriteZMessage("I: [frontend sending to backend] ({0})", incoming, workerIdentity.ReadString()); } backend.Send(incoming); } } else { if (error == ZError.ETERM) { break; // Interrupted } if (error != ZError.EAGAIN) { throw new ZException(error); } } } // We handle heartbeating after any socket activity. First, we send // heartbeats to any idle workers if it's time. Then, we purge any // dead workers: if (DateTime.UtcNow > heartbeat_at) { heartbeat_at = DateTime.UtcNow + Worker.PPP_HEARTBEAT_INTERVAL; foreach (Worker worker in workers) { using (var outgoing = new ZMessage()) { outgoing.Add(ZFrame.CopyFrom(worker.Identity)); outgoing.Add(new ZFrame(Worker.PPP_HEARTBEAT)); Console.WriteLine("I: sending heartbeat ({0})", worker.IdentityString); backend.Send(outgoing); } } } workers.Purge(); } // When we're done, clean up properly foreach (Worker worker in workers) { worker.Dispose(); } } }