// --------------------------------------------------------------------- // This is our client task // It connects to the server, and then sends a request once per second // It collects responses as they arrive, and it prints them out. We will // run several client tasks in parallel, each with a different random ID. static void ClientTask() { using (Context ctx = new Context(1)) { using (Socket client = ctx.Socket(SocketType.XREQ)) { // Generate printable identity for the client ZHelpers.SetID(client, Encoding.Unicode); string identity = client.IdentityToString(Encoding.Unicode); client.Connect("tcp://localhost:5570"); client.PollInHandler += (skt, revents) => { ZMessage zmsg = new ZMessage(skt); Console.WriteLine("{0} : {1}", identity, zmsg.BodyToString()); }; int requestNbr = 0; while (true) { // Tick once per second, pulling in arriving messages for (int centitick = 0; centitick < 100; centitick++) { Context.Poller(new List<Socket>(new Socket[] { client }), 10000); } ZMessage zmsg = new ZMessage(""); zmsg.StringToBody(String.Format("request: {0}", ++requestNbr)); zmsg.Send(client); } } } }
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; } } } } }
// Accept a request and reply with the same text a random number of // times, with random delays between replies. // static void ServerWorker(object ctx) { Random rand = new Random(DateTime.Now.Millisecond); using (Socket worker = ((Context)ctx).Socket(SocketType.DEALER)) { worker.Connect("inproc://backend"); while (true) { // The DEALER socket gives us the address envelope and message ZMessage zmsg = new ZMessage(worker); // Send 0..4 replies back int replies = rand.Next(5); for (int reply = 0; reply < replies; reply++) { Thread.Sleep(rand.Next(1, 1000)); zmsg.Send(worker); } } } }
// Worker using REQ socket to do LRU routing // static void WorkerTask() { using (Context ctx = new Context(1)) { using (Socket worker = ctx.Socket(SocketType.REQ)) { ZHelpers.SetID(worker, Encoding.Unicode); worker.Connect("tcp://localhost:5556"); // Tell broker we're ready for work worker.Send("READY", Encoding.Unicode); while (true) { ZMessage zmsg = new ZMessage(worker); Console.WriteLine("Worker: {0}", Encoding.Unicode.GetString(zmsg.Body)); zmsg.StringToBody("OK"); zmsg.Send(worker); } } } }
// --------------------------------------------------------------------- // This is our server task // It uses the multithreaded server model to deal requests out to a pool // of workers and route replies back to clients. One worker can handle // one request at a time but one client can talk to multiple workers at // once. private static void ServerTask() { var workers = new List <Thread>(5); using (var context = ZmqContext.Create()) { using (ZmqSocket frontend = context.CreateSocket(SocketType.ROUTER), backend = context.CreateSocket(SocketType.DEALER)) { frontend.Bind("tcp://*:5570"); backend.Bind("inproc://backend"); for (int workerNumber = 0; workerNumber < 5; workerNumber++) { workers.Add(new Thread(ServerWorker)); workers[workerNumber].Start(context); } // Switch messages between frontend and backend frontend.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); zmsg.Send(backend); }; backend.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); zmsg.Send(frontend); }; var poller = new Poller(new List <ZmqSocket> { frontend, backend }); while (true) { poller.Poll(); } } } }
// --------------------------------------------------------------------- // This is our server task // It uses the multithreaded server model to deal requests out to a pool // of workers and route replies back to clients. One worker can handle // one request at a time but one client can talk to multiple workers at // once. private static void ServerTask() { var workers = new List <Thread>(5); using (var context = new Context(1)) { using (Socket frontend = context.Socket(SocketType.ROUTER), backend = context.Socket(SocketType.DEALER)) { frontend.Bind("tcp://*:5570"); backend.Bind("inproc://backend"); for (int workerNumber = 0; workerNumber < 5; workerNumber++) { workers.Add(new Thread(ServerWorker)); workers[workerNumber].Start(context); } // Switch messages between frontend and backend frontend.PollInHandler += (socket, revents) => { var zmsg = new ZMessage(socket); zmsg.Send(backend); }; backend.PollInHandler += (socket, revents) => { var zmsg = new ZMessage(socket); zmsg.Send(frontend); }; var sockets = new List <Socket> { frontend, backend }; while (true) { Context.Poller(sockets); } } } }
static void Main(string[] args) { using (var context = ZmqContext.Create()) { using (var worker = context.CreateSocket(SocketType.REQ)) { var randomizer = new Random(DateTime.Now.Millisecond); var identity = ZHelpers.SetID(worker, Encoding.Unicode); worker.Connect("tcp://localhost:5556"); Console.WriteLine("I: {0} worker ready", identity); worker.Send("READY", Encoding.Unicode); var cycles = 0; while (true) { var zmsg = new ZMessage(worker); cycles += 1; if (cycles > 3 && randomizer.Next(0, 5) == 0) { Console.WriteLine("I: {0} simulating a crash", identity); break; } else if (cycles > 3 && randomizer.Next(0, 5) == 0) { Console.WriteLine("I: {0} simulating CPU overload", identity); System.Threading.Thread.Sleep(3000); } Console.WriteLine("I: {0} normal reply", identity); System.Threading.Thread.Sleep(1000); zmsg.Send(worker); } } } }
// --------------------------------------------------------------------- // This is our client task // It connects to the server, and then sends a request once per second // It collects responses as they arrive, and it prints them out. We will // run several client tasks in parallel, each with a different random ID. public static void ClientTask() { using (var context = ZmqContext.Create()) { using (ZmqSocket client = context.CreateSocket(SocketType.DEALER)) { // Generate printable identity for the client string identity = ZHelpers.SetID(client, Encoding.Unicode); client.Connect("tcp://localhost:5570"); client.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); Console.WriteLine("{0} : {1}", identity, zmsg.BodyToString()); }; int requestNumber = 0; var poller = new Poller(new List <ZmqSocket> { client }); while (true) { // Tick once per second, pulling in arriving messages for (int centitick = 0; centitick < 100; centitick++) { poller.Poll(TimeSpan.FromMilliseconds(10)); } var zmsg = new ZMessage(""); zmsg.StringToBody(String.Format("request: {0}", ++requestNumber)); zmsg.Send(client); } } } }
// --------------------------------------------------------------------- // This is our server task // It uses the multithreaded server model to deal requests out to a pool // of workers and route replies back to clients. One worker can handle // one request at a time but one client can talk to multiple workers at // once. static void ServerTask() { List<Thread> workers = new List<Thread>(5); using (Context ctx = new Context(1)) { using (Socket frontend = ctx.Socket(SocketType.XREP), backend = ctx.Socket(SocketType.XREQ)) { // Frontend socket talks to clients over TCP frontend.Bind("tcp://*:5570"); // Backend socket talks to workers over inproc backend.Bind("inproc://backend"); // Launch pool of worker threads, precise number is not critical for (int threadNbr = 0; threadNbr < 5; threadNbr++) { workers.Add(new Thread(ServerWorker)); workers[threadNbr].Start(ctx); } // Connect backend to frontend via a queue device // We could do this: // zmq_device (ZMQ_QUEUE, frontend, backend); // But doing it ourselves means we can debug this more easily // Switch messages between frontend and backend frontend.PollInHandler += (skt, revents) => { ZMessage zmsg = new ZMessage(skt); zmsg.Send(backend); }; backend.PollInHandler += (skt, revents) => { ZMessage zmsg = new ZMessage(skt); zmsg.Send(frontend); }; List<Socket> sockets = new List<Socket>(); sockets.Add(frontend); sockets.Add(backend); while(true){ Context.Poller(sockets); } } } }
private static void WorkerTask() { using (var ctx = ZmqContext.Create()) { using (var worker = ctx.CreateSocket(SocketType.REQ)) { ZHelpers.SetID(worker, Encoding.Unicode); worker.Connect(localBeAddress); var msg = new ZMessage("READY"); msg.Send(worker); while (true) { var recvMsg = new ZMessage(worker); Console.WriteLine("Worker: {0}", recvMsg.BodyToString()); Thread.Sleep(1000); recvMsg.StringToBody("OK"); recvMsg.Send(worker); //var okmsg = new ZMessage("OK"); //okmsg.Send(worker); } } } }
// Accept a request and reply with the same text a random number of // times, with random delays between replies. // static void ServerWorker(object ctx) { Random rand = new Random(DateTime.Now.Millisecond); using (Socket worker = ((Context)ctx).Socket(SocketType.XREQ)) { worker.Connect("inproc://backend"); while (true) { // The XREQ socket gives us the address envelope and message ZMessage zmsg = new ZMessage(worker); // Send 0..4 replies back int replies = rand.Next(5); for (int reply = 0; reply < replies; reply++) { Thread.Sleep(rand.Next(1, 1000)); zmsg.Send(worker); } } } }
// --------------------------------------------------------------------- // This is our server task // It uses the multithreaded server model to deal requests out to a pool // of workers and route replies back to clients. One worker can handle // one request at a time but one client can talk to multiple workers at // once. private static void ServerTask() { var workers = new List <Thread>(5); using (var context = ZmqContext.Create()) { using (ZmqSocket frontend = context.CreateSocket(SocketType.ROUTER), backend = context.CreateSocket(SocketType.DEALER)) { frontend.Bind("tcp://*:5570"); backend.Bind("inproc://backend"); for (int workerNumber = 0; workerNumber < 5; workerNumber++) { workers.Add(new Thread(ServerWorker)); workers[workerNumber].Start(context); } // Switch messages between frontend and backend frontend.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); zmsg.Send(backend); }; backend.ReceiveReady += (s, e) => { var zmsg = new ZMessage(e.Socket); string lol = zmsg.BodyToString(); JSONMessage m = JsonConvert.DeserializeObject <JSONMessage>(lol); if (m.Function != null) { switch (m.Function) { case "RegisterService": Console.WriteLine("RegisterService"); m.ReponseString = "OK"; Repository.RegisterService(m.Parameters[0], m.Parameters[1]); break; case "GetServiceLocation": Console.WriteLine("GetServiceLocation"); string locat = Repository.GetServiceLocation(m.Parameters[0]); m.ReponseString = locat; break; case "Alive": Console.WriteLine("Alive"); Repository.Alive(m.Parameters[0]); m.ReponseString = "OK"; break; case "Unregister": Console.WriteLine("Unregister"); Repository.Unregister(m.Parameters[0]); m.ReponseString = "OK"; break; default: Console.WriteLine("Unknown: " + m.Function); break; } } string json = JsonConvert.SerializeObject(m); zmsg.StringToBody(json); zmsg.Send(frontend); }; var poller = new Poller(new List <ZmqSocket> { frontend, backend }); while (true) { poller.Poll(); } } } }
private static void SendReply(ZMessage msg, ZmqSocket cloudfe, ZmqSocket localfe) { var address = Encoding.Unicode.GetString(msg.Address); // Route reply to cloud if it's addressed to a broker if (peers.Count(peerAddress => peerAddress == address) == 1) { Console.WriteLine("Sending to cloud frontend"); msg.Send(cloudfe); } else { Console.WriteLine("Sending to local frontend"); msg.Send(localfe); } }
static void Main(string[] args) { using (var context = new Context(1)) { int interval = INTERVAL_INIT; int liveness = HEARTBEAT_LIVENESS; while (true) { int cylces = 0; using (Socket worker = ConnectWorker(context)) { worker.PollInHandler += (socket, revents) => { var zmsg = new ZMessage(socket); byte[] identity = zmsg.Unwrap(); switch (Encoding.Unicode.GetString(zmsg.Address)) { case PPP_HEARTBEAT: interval = INTERVAL_INIT; liveness = HEARTBEAT_LIVENESS; break; default: if (zmsg.FrameCount > 1) { if (!doTheWork(cylces++)) { break; } interval = INTERVAL_INIT; liveness = HEARTBEAT_LIVENESS; Console.WriteLine("W: work completed"); zmsg.Send(worker); } else { Console.WriteLine("E: invalied message {0}", identity); } break; } ; }; //Send out heartbeats at regular intervals DateTime heartbeat_at = DateTime.Now.AddMilliseconds(HEARTBEAT_INTERVAL); while (true) { List <Socket> pollItems = new List <Socket>(new Socket[] { worker }); Context.Poller(pollItems, HEARTBEAT_INTERVAL * 1000); //If liveness hits zero, queue is considered disconnected if (--liveness <= 0) { Console.WriteLine("W: heartbeat failure, can't reach queue."); Console.WriteLine("W: reconnecting in {0} msecs...", interval); try { Thread.Sleep(interval); } catch (System.Exception ex) { Console.WriteLine(ex.Message); } //Exponential Backoff if (interval < INTERVAL_MAX) { interval *= 2; } liveness = HEARTBEAT_LIVENESS; //Break the while loop and start the connection over break; } //Send heartbeat to queue if it's time if (DateTime.Now > heartbeat_at) { heartbeat_at = DateTime.Now.AddMilliseconds(HEARTBEAT_INTERVAL); ZMessage zmsg = new ZMessage(PPP_HEARTBEAT); zmsg.Send(worker); } } } } } }
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; } } } } }
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 })); } } } } }
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 })); } } } } }
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); } } } } }
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); } } } } }