Example #1
0
            //  .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);
                    }
                }
            }
Example #2
0
        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;
                        }
                    }
                }
            }
        }
Example #3
0
        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;
                        }
                    }
                }
            }
        }
Example #4
0
        //  .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);
        }
Example #5
0
        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);
                        }
                    }
                }
            }
        }
Example #6
0
            //  .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);
            }
Example #7
0
            //  .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);
                    }
                }
            }
Example #8
0
            //  .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");
                    }
                }
            }
Example #9
0
        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 }));
                        }
                    }
                }
            }
        }
Example #10
0
        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;
                        }
                    }
                }
            }
        }
Example #11
0
            //  .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);
                    }
                }
            }
Example #12
0
        //  .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);
        }
Example #13
0
        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 }));
                        }
                    }
                }
            }
        }
Example #14
0
            //  .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");
                        }
                    }
            }
Example #15
0
        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);
                        }
                    }
                }
            }
        }
Example #16
0
			//  .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;
			}