// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if (msg.Count < 2) { throw new InvalidOperationException(); } using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "404"; } else { returnCode = "501"; } var client = msg.Unwrap(); msg.Clear(); msg.Add(new ZFrame(returnCode)); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
static void Main(string[] args) { using (var context = ZmqContext.Create()) { using (ZmqSocket frontend = context.CreateSocket(SocketType.ROUTER), backend = context.CreateSocket(SocketType.ROUTER)) { frontend.Bind("tcp://*:5555"); // For Clients backend.Bind("tcp://*:5556"); // For Workers // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers var workerQueue = new Queue <byte[]>(); // Handle worker activity on backend backend.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); // Use worker address for LRU routing workerQueue.Enqueue(zmsg.Unwrap()); // Forward message to client if it's not a READY if (!Encoding.Unicode.GetString(zmsg.Address).Equals(LRU_READY)) { zmsg.Send(frontend); } }; frontend.ReceiveReady += (s, e) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address var zmsg = new ZMessage(e.Socket); zmsg.Wrap(workerQueue.Dequeue(), new byte[0]); zmsg.Send(backend); }; var poller = new Poller(new ZmqSocket[] { frontend, backend }); while (true) { //int rc = ZmqContext.Poller(workerQueue.Count > 0 // ? new List<ZmqSocket>(new ZmqSocket[] {frontend, backend}) // : new List<ZmqSocket>(new ZmqSocket[] {backend})); int rc = poller.Poll(); if (rc == -1) { break; } } } } }
static void Main(string[] args) { using (var context = ZmqContext.Create()) { using (ZmqSocket frontend = context.CreateSocket(SocketType.ROUTER), backend = context.CreateSocket(SocketType.ROUTER)) { frontend.Bind("tcp://*:5555"); // For Clients backend.Bind("tcp://*:5556"); // For Workers // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers var workerQueue = new Queue<byte[]>(); // Handle worker activity on backend backend.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); // Use worker address for LRU routing workerQueue.Enqueue(zmsg.Unwrap()); // Forward message to client if it's not a READY if (!Encoding.Unicode.GetString(zmsg.Address).Equals(LRU_READY)) { zmsg.Send(frontend); } }; frontend.ReceiveReady += (s, e) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address var zmsg = new ZMessage(e.Socket); zmsg.Wrap(workerQueue.Dequeue(), new byte[0]); zmsg.Send(backend); }; var poller = new Poller(new ZmqSocket[] { frontend, backend }); while (true) { //int rc = ZmqContext.Poller(workerQueue.Count > 0 // ? new List<ZmqSocket>(new ZmqSocket[] {frontend, backend}) // : new List<ZmqSocket>(new ZmqSocket[] {backend})); int rc = poller.Poll(); if (rc == -1) { break; } } } } }
// .split worker send method // This method formats and sends a command to a worker. The caller may // also provide a command option, and a message payload: public void Send(string command, string option, ZMessage msg) { msg = msg != null ? msg.Duplicate() : new ZMessage(); // Stack protocol envelope to start of message if (!string.IsNullOrEmpty(option)) { msg.Prepend(new ZFrame(option)); } msg.Prepend(new ZFrame(command)); msg.Prepend(new ZFrame(MdpCommon.MDPW_WORKER)); // Stack routing envelope to start of message msg.Wrap(Identity.Duplicate()); if (Broker.Verbose) { msg.DumpZmsg("I: sending '{0:X}|{0}' to worker", command.ToMdCmd()); } Broker.Socket.Send(msg); }
static void Main(string[] args) { using (var context = new Context(1)) { using (Socket frontend = context.Socket(SocketType.ROUTER), backend = context.Socket(SocketType.ROUTER)) { frontend.Bind("tcp://*:5555"); // For Clients backend.Bind("tcp://*:5556"); // For Workers // Queue of available workers var workerQueue = new List <Worker>(); backend.PollInHandler += (socket, revents) => { var zmsg = new ZMessage(socket); byte[] identity = zmsg.Unwrap(); //Any sign of life from worker means it's ready, Only add it to the queue if it's not in there already Worker worker = null; if (workerQueue.Count > 0) { var workers = workerQueue.Where(x => x.address.SequenceEqual(identity)); if (workers.Count() > 0) { worker = workers.Single(); } } if (worker == null) { workerQueue.Add(new Worker(identity)); } //Return reply to client if it's not a control message switch (Encoding.Unicode.GetString(zmsg.Address)) { case PPP_READY: Console.WriteLine("Worker " + Encoding.Unicode.GetString(identity) + " is ready..."); break; case PPP_HEARTBEAT: bool found = false; //Worker Refresh if (worker != null) { found = true; worker.ResetExpiry(); } if (!found) { Console.WriteLine("E: worker " + Encoding.Unicode.GetString(identity) + " not ready..."); } break; default: zmsg.Send(frontend); break; } ; }; frontend.PollInHandler += (socket, revents) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address var zmsg = new ZMessage(socket); Worker w = workerQueue[0]; zmsg.Wrap(w.address, new byte[0]); workerQueue.RemoveAt(0); zmsg.Send(backend); }; DateTime heartbeat_at = DateTime.Now.AddMilliseconds(HEARTBEAT_INTERVAL); while (true) { //Only poll frontend only if there are workers ready if (workerQueue.Count > 0) { List <Socket> pollItems = new List <Socket>(new Socket[] { frontend, backend }); Context.Poller(pollItems, HEARTBEAT_INTERVAL * 1000); } else { List <ZMQ.Socket> pollItems = new List <Socket>(new Socket[] { backend }); Context.Poller(pollItems, HEARTBEAT_INTERVAL * 1000); } //Send heartbeats to idle workers if it's time if (DateTime.Now >= heartbeat_at) { foreach (var worker in workerQueue) { ZMessage zmsg = new ZMessage(PPP_HEARTBEAT); zmsg.Wrap(worker.address, new byte[0]); zmsg.Send(backend); } heartbeat_at = DateTime.Now.AddMilliseconds(HEARTBEAT_INTERVAL); } } } } }
// .split worker send method // This method formats and sends a command to a worker. The caller may // also provide a command option, and a message payload: public void Send(string command, string option, ZMessage msg) { msg = msg != null ? msg.Duplicate() : new ZMessage(); // Stack protocol envelope to start of message if (!string.IsNullOrEmpty(option)) msg.Prepend(new ZFrame(option)); msg.Prepend(new ZFrame(command)); msg.Prepend(new ZFrame(MdpCommon.MDPW_WORKER)); // Stack routing envelope to start of message msg.Wrap(Identity.Duplicate()); if(Broker.Verbose) msg.DumpZmsg("I: sending '{0:X}|{0}' to worker", command.ToMdCmd()); Broker.Socket.Send(msg); }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if(msg.Count < 2) throw new InvalidOperationException(); using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "404"; } else returnCode = "501"; var client = msg.Unwrap(); msg.Clear(); msg.Add(new ZFrame(returnCode)); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
// .split broker worker_msg method // This method processes one READY, REPLY, HEARTBEAT, or // DISCONNECT message sent to the broker by a worker: public void WorkerMsg(ZFrame sender, ZMessage msg) { if(msg.Count < 1) // At least, command throw new InvalidOperationException(); ZFrame command = msg.Pop(); //string id_string = sender.ReadString(); bool isWorkerReady; //string id_string; using (var sfrm = sender.Duplicate()) { var idString = sfrm.Read().ToHexString(); isWorkerReady = Workers.ContainsKey(idString); } Worker worker = RequireWorker(sender); using (msg) using (command) { if (command.StrHexEq(MdpCommon.MdpwCmd.READY)) { if (isWorkerReady) // Not first command in session worker.Delete(true); else if (command.Length >= 4 && command.ToString().StartsWith("mmi.")) // Reserd servicee name worker.Delete(true); else { // Attach worker to service and mark as idle using (ZFrame serviceFrame = msg.Pop()) { worker.Service = RequireService(serviceFrame); worker.Service.Workers++; worker.Waiting(); } } } else if (command.StrHexEq(MdpCommon.MdpwCmd.REPLY)) { if (isWorkerReady) { // Remove and save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(new ZFrame(worker.Service.Name)); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); worker.Waiting(); } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { if (isWorkerReady) { worker.Expiry = DateTime.UtcNow + MdpCommon.HEARTBEAT_EXPIRY; } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) worker.Delete(false); else { msg.DumpZmsg("E: invalid input message"); } } }
static void Main(string[] args) { List<Thread> workers = new List<Thread>(); List<Thread> clients = new List<Thread>(); // Prepare our context and sockets using (Context ctx = new Context(1)) { using (Socket frontend = ctx.Socket(SocketType.XREP), backend = ctx.Socket(SocketType.XREP)) { frontend.Bind("tcp://*:5555"); backend.Bind("tcp://*:5556"); int clientNbr; for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++) { clients.Add(new Thread(ClientTask)); clients[clientNbr].Start(); } for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) { workers.Add(new Thread(WorkerTask)); workers[workerNbr].Start(); } // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers Queue<byte[]> workerQueue = new Queue<byte[]>(); // Handle worker activity on backend backend.PollInHandler += (skt, revents) => { ZMessage zmsg = new ZMessage(skt); // Use worker address for LRU routing workerQueue.Enqueue(zmsg.Unwrap()); // Forward message to client if it's not a READY if (!Encoding.Unicode.GetString(zmsg.Address).Equals("READY")) { zmsg.Send(frontend); clientNbr--; // Exit after N messages } }; frontend.PollInHandler += (skt, revents) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address ZMessage zmsg = new ZMessage(skt); zmsg.Wrap(workerQueue.Dequeue(), new byte[0]); zmsg.Send(backend); }; while (clientNbr > 0) { // Exit after N messages if (workerQueue.Count > 0) { Context.Poller(new List<Socket>(new Socket[] { frontend, backend })); } else { Context.Poller(new List<Socket>(new Socket[] { backend })); } } } } }
public static void Main(string[] args) { var workers = new List <Thread>(); var clients = new List <Thread>(); // Prepare our context and sockets using (var ctx = new Context(1)) { using (Socket frontend = ctx.Socket(SocketType.ROUTER), backend = ctx.Socket(SocketType.ROUTER)) { frontend.Bind("tcp://*:5555"); backend.Bind("tcp://*:5556"); int clientId; for (clientId = 0; clientId < Program.clients; clientId++) { clients.Add(new Thread(ClientTask)); clients[clientId].Start(); } for (int workerId = 0; workerId < Program.workers; workerId++) { workers.Add(new Thread(WorkerTask)); workers[workerId].Start(); } // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers var workerQueue = new Queue <byte[]>(); // Handle worker activity on backend backend.PollInHandler += (socket, revents) => { var zmsg = new ZMessage(socket); // Use worker address for LRU routing workerQueue.Enqueue(zmsg.Unwrap()); // Forward message to client if it's not a READY if (!Encoding.Unicode.GetString(zmsg.Address).Equals("READY")) { zmsg.Send(frontend); } }; frontend.PollInHandler += (socket, revents) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address var zmsg = new ZMessage(socket); zmsg.Wrap(workerQueue.Dequeue(), new byte[0]); zmsg.Send(backend); }; while (true) { int rc = Context.Poller(workerQueue.Count > 0 ? new List <Socket>(new Socket[] { frontend, backend }) : new List <Socket>(new Socket[] { backend })); if (rc == -1) { break; } } } } }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if(msg.Count < 2) throw new InvalidOperationException(); using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "400"; } else returnCode = "501"; using (var resetableFrame = msg.Pop()) { msg.Prepend(new ZFrame(returnCode)); } //ToDo check c implementation throw new NotImplementedException("ToDo: fix this section, never tested. contains errors mmi services never called with the mdclient/mdbroker/mdworker examples"); //## following code has some errors // Remove & save client return envelope and insert the // protocol header and Service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
// .split recv method // This is the {{recv}} method; it's a little misnamed because it first sends // any reply and then waits for a new request. If you have a better name // for this, let me know. // Send reply, if any, to broker and wait for next request. public ZMessage Recv(ZMessage reply, CancellationTokenSource cancellor) { if (reply == null && _expectReply) { throw new InvalidOperationException(); } if (reply != null) { if (_replyTo == null) { throw new InvalidOperationException(); } reply.Wrap(_replyTo); SendToBroker(MdpCommon.MdpwCmd.REPLY.ToHexString(), string.Empty, reply); } _expectReply = true; while (true) { if (cancellor.IsCancellationRequested || (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) { _context.Shutdown(); } var p = ZPollItem.CreateReceiver(); ZMessage msg; ZError error; if (Worker.PollIn(p, out msg, out error, Heartbeat)) { using (msg) { // If we got a reply if (Verbose) { msg.DumpZmsg("I: received message from broker:"); } Liveness = MdpCommon.HEARTBEAT_LIVENESS; // Don't try to handle errors, just assert noisily if (msg.Count < 3) { throw new InvalidOperationException(); } using (ZFrame empty = msg.Pop()) { if (!empty.ToString().Equals("")) { throw new InvalidOperationException(); } } using (ZFrame header = msg.Pop()) { if (!header.ToString().Equals(MdpCommon.MDPW_WORKER)) { throw new InvalidOperationException(); } } //header.ReadString().Equals(MDPW_WORKER); using (ZFrame command = msg.Pop()) { if (command.StrHexEq(MdpCommon.MdpwCmd.REQUEST)) { // We should pop and save as many addresses as there are // up to a null part, but for now, just save one... _replyTo = msg.Unwrap(); // .split process message // Here is where we actually have a message to process; we // return it to the caller application: return(msg.Duplicate()); } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { // Do nothing for heartbeats } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) { ConnectToBroker(); } else { "E: invalid input message: '{0}'".DumpString(command.ToString()); } } } } else if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); break; // Interrupted } else if (Equals(error, ZError.EAGAIN) && --Liveness == 0) { if (Verbose) { "W: disconnected from broker - retrying...".DumpString(); } Thread.Sleep(Reconnect); ConnectToBroker(); } // Send HEARTBEAT if it's time if (DateTime.UtcNow > HeartbeatAt) { SendToBroker(MdpCommon.MdpwCmd.HEARTBEAT.ToHexString(), null, null); HeartbeatAt = DateTime.UtcNow + Heartbeat; } } if (cancellor.IsCancellationRequested) { "W: interrupt received, killing worker...\n".DumpString(); } return(null); }
static void Main(string[] args) { List <Thread> workers = new List <Thread>(); List <Thread> clients = new List <Thread>(); // Prepare our context and sockets using (Context ctx = new Context(1)) { using (Socket frontend = ctx.Socket(SocketType.ROUTER), backend = ctx.Socket(SocketType.ROUTER)) { frontend.Bind("tcp://*:5555"); backend.Bind("tcp://*:5556"); int clientNbr; for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++) { clients.Add(new Thread(ClientTask)); clients[clientNbr].Start(); } for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) { workers.Add(new Thread(WorkerTask)); workers[workerNbr].Start(); } // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers Queue <byte[]> workerQueue = new Queue <byte[]>(); // Handle worker activity on backend backend.PollInHandler += (skt, revents) => { ZMessage zmsg = new ZMessage(skt); // Use worker address for LRU routing workerQueue.Enqueue(zmsg.Unwrap()); // Forward message to client if it's not a READY if (!Encoding.Unicode.GetString(zmsg.Address).Equals("READY")) { zmsg.Send(frontend); clientNbr--; // Exit after N messages } }; frontend.PollInHandler += (skt, revents) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address ZMessage zmsg = new ZMessage(skt); zmsg.Wrap(workerQueue.Dequeue(), new byte[0]); zmsg.Send(backend); }; while (clientNbr > 0) // Exit after N messages { if (workerQueue.Count > 0) { Context.Poller(new List <Socket>(new Socket[] { frontend, backend })); } else { Context.Poller(new List <Socket>(new Socket[] { backend })); } } } } }
// .split broker worker_msg method // This method processes one READY, REPLY, HEARTBEAT, or // DISCONNECT message sent to the broker by a worker: public void WorkerMsg(ZFrame sender, ZMessage msg) { if (msg.Count < 1) // At least, command { throw new InvalidOperationException(); } ZFrame command = msg.Pop(); //string id_string = sender.ReadString(); bool isWorkerReady; //string id_string; using (var sfrm = sender.Duplicate()) { var idString = sfrm.Read().ToHexString(); isWorkerReady = Workers.ContainsKey(idString); } Worker worker = RequireWorker(sender); using (msg) using (command) { if (command.StrHexEq(MdpCommon.MdpwCmd.READY)) { if (isWorkerReady) { // Not first command in session worker.Delete(true); } else if (command.Length >= 4 && command.ToString().StartsWith("mmi.")) { // Reserd servicee name worker.Delete(true); } else { // Attach worker to service and mark as idle using (ZFrame serviceFrame = msg.Pop()) { worker.Service = RequireService(serviceFrame); worker.Service.Workers++; worker.Waiting(); } } } else if (command.StrHexEq(MdpCommon.MdpwCmd.REPLY)) { if (isWorkerReady) { // Remove and save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(new ZFrame(worker.Service.Name)); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); worker.Waiting(); } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { if (isWorkerReady) { worker.Expiry = DateTime.UtcNow + MdpCommon.HEARTBEAT_EXPIRY; } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) { worker.Delete(false); } else { msg.DumpZmsg("E: invalid input message"); } } }
static void Main(string[] args) { using (var context = ZmqContext.Create()) { using (ZmqSocket frontend = context.CreateSocket(SocketType.ROUTER), backend = context.CreateSocket(SocketType.ROUTER)) { frontend.Bind("tcp://*:5555"); // For Clients backend.Bind("tcp://*:5556"); // For Workers // Queue of available workers var workerQueue = new List<Worker>(); backend.ReceiveReady += (socket, e) => { var zmsg = new ZMessage(e.Socket); byte[] identity = zmsg.Unwrap(); //Any sign of life from worker means it's ready, Only add it to the queue if it's not in there already Worker worker = null; if (workerQueue.Count > 0) { var workers = workerQueue.Where(x => x.address.SequenceEqual(identity)); if (workers.Any()) worker = workers.Single(); } if (worker == null) { workerQueue.Add(new Worker(identity)); } //Return reply to client if it's not a control message switch (Encoding.Unicode.GetString(zmsg.Address)) { case PPP_READY: Console.WriteLine("Worker " + Encoding.Unicode.GetString(identity) + " is ready..."); break; case PPP_HEARTBEAT: bool found = false; //Worker Refresh if (worker != null) { found = true; worker.ResetExpiry(); } if (!found) { Console.WriteLine("E: worker " + Encoding.Unicode.GetString(identity) + " not ready..."); } break; default: zmsg.Send(frontend); break; }; }; frontend.ReceiveReady += (socket, e) => { // Now get next client request, route to next worker // Dequeue and drop the next worker address var zmsg = new ZMessage(e.Socket); Worker w = workerQueue[0]; zmsg.Wrap(w.address, new byte[0]); workerQueue.RemoveAt(0); zmsg.Send(backend); }; var poller = new Poller(new List<ZmqSocket> { frontend, backend }); DateTime heartbeat_at = DateTime.Now.AddMilliseconds(HEARTBEAT_INTERVAL); while (true) { //Only poll frontend only if there are workers ready if (workerQueue.Count > 0) { //List<ZmqSocket> pollItems = new List<ZmqSocket>(new ZmqSocket[] { frontend, backend }); poller.Poll(TimeSpan.FromMilliseconds(HEARTBEAT_INTERVAL * 1000)); } else { //List<ZmqSocket> pollItems = new List<ZmqSocket>(new ZmqSocket[] { backend }); poller.Poll(TimeSpan.FromMilliseconds(HEARTBEAT_INTERVAL * 1000)); } //Send heartbeats to idle workers if it's time if (DateTime.Now >= heartbeat_at) { foreach (var worker in workerQueue) { ZMessage zmsg = new ZMessage(PPP_HEARTBEAT); zmsg.Wrap(worker.address, new byte[0]); zmsg.Send(backend); } heartbeat_at = DateTime.Now.AddMilliseconds(HEARTBEAT_INTERVAL); } } } } }
// .split recv method // This is the {{recv}} method; it's a little misnamed because it first sends // any reply and then waits for a new request. If you have a better name // for this, let me know. // Send reply, if any, to broker and wait for next request. public ZMessage Recv(ZMessage reply, CancellationTokenSource cancellor) { if (reply == null && _expectReply) throw new InvalidOperationException(); if (reply != null) { if(_replyTo == null) throw new InvalidOperationException(); reply.Wrap(_replyTo); SendToBroker(MdpCommon.MdpwCmd.REPLY.ToHexString(), string.Empty, reply); } _expectReply = true; while (true) { if (cancellor.IsCancellationRequested || (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) _context.Shutdown(); var p = ZPollItem.CreateReceiver(); ZMessage msg; ZError error; if (Worker.PollIn(p, out msg, out error, Heartbeat)) { using (msg) { // If we got a reply if (Verbose) msg.DumpZmsg("I: received message from broker:"); Liveness = MdpCommon.HEARTBEAT_LIVENESS; // Don't try to handle errors, just assert noisily if(msg.Count < 3) throw new InvalidOperationException(); using (ZFrame empty = msg.Pop()) { if (!empty.ToString().Equals("")) throw new InvalidOperationException(); } using (ZFrame header = msg.Pop()) { if (!header.ToString().Equals(MdpCommon.MDPW_WORKER)) throw new InvalidOperationException(); } //header.ReadString().Equals(MDPW_WORKER); using (ZFrame command = msg.Pop()) { if (command.StrHexEq(MdpCommon.MdpwCmd.REQUEST)) { // We should pop and save as many addresses as there are // up to a null part, but for now, just save one... _replyTo = msg.Unwrap(); // .split process message // Here is where we actually have a message to process; we // return it to the caller application: return msg.Duplicate(); } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { // Do nothing for heartbeats } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) { ConnectToBroker(); } else "E: invalid input message: '{0}'".DumpString(command.ToString()); } } } else if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); break; // Interrupted } else if (Equals(error, ZError.EAGAIN) && --Liveness == 0) { if (Verbose) "W: disconnected from broker - retrying...".DumpString(); Thread.Sleep(Reconnect); ConnectToBroker(); } // Send HEARTBEAT if it's time if (DateTime.UtcNow > HeartbeatAt) { SendToBroker(MdpCommon.MdpwCmd.HEARTBEAT.ToHexString(), null, null); HeartbeatAt = DateTime.UtcNow + Heartbeat; } } if (cancellor.IsCancellationRequested) "W: interrupt received, killing worker...\n".DumpString(); return null; }