CancelAndJoin() public method

Cancel the poller job when PollTillCancelled is called and wait for the PollTillCancelled to complete
public CancelAndJoin ( ) : void
return void
示例#1
0
        /// <summary>
        /// Release any contained resources.
        /// </summary>
        /// <param name="disposing">set this to true if releasing managed resources</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
            {
                return;
            }

            if (!m_ownPoller && !m_poller.IsStarted)
            {
                DisposeSynced();
                return;
            }

            // disposing on the scheduler thread
            var task = new Task(DisposeSynced);

            task.Start(this);
            task.Wait();

            // poller cannot be stopped from poller thread
            if (m_ownPoller)
            {
                m_poller.CancelAndJoin();
                m_poller.Dispose();
            }
            m_isSchedulerThread.Dispose();
        }
示例#2
0
        public void Dispose()
        {
            // disposing on the scheduler thread
            Task task = new Task(DisposeSynced);

            task.Start(this);
            task.Wait();

            // poller cannot be stopped from poller thread
            if (m_ownPoller)
            {
                m_poller.CancelAndJoin();
            }
        }
示例#3
0
        public void Send_CorrectInputWithLogging_ShouldReturnCorrectReply()
        {
            const string hostAddress = "tcp://localhost:5555";
            var loggingMessages = new List<string>();

            // setup the counter socket for communication
            using (var context = NetMQContext.Create())
            using (var broker = context.CreateRouterSocket())
            using (var poller = new Poller())
            using (var session = new MDPClient(hostAddress))
            {
                broker.Bind(hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMessage();
                    // we expect to receive a 4 Frame message
                    // [client adrR][e][mdp header][service][request]
                    if (msg.FrameCount != 5)
                        Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount);
                    // REQUEST socket will strip the his address + empty frame
                    // ROUTER has to add the address prelude in order to identify the correct socket(!)
                    // [client adr][e][mdp header][service][reply]
                    var request = msg.Last.ConvertToString(); // get the request string
                    msg.RemoveFrame(msg.Last); // remove the request frame
                    msg.Append(new NetMQFrame(request + " OK")); // append the reply frame
                    e.Socket.SendMessage(msg);
                };

                poller.AddSocket(broker);
                Task.Factory.StartNew(poller.PollTillCancelled);

                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info);
                // well formed message
                var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") });
                // correct call
                var reply = session.Send("echo", requestMessage);

                poller.CancelAndJoin();
                poller.RemoveSocket(broker);

                Assert.That(reply.FrameCount, Is.EqualTo(1));
                Assert.That(reply.First.ConvertToString(), Is.EqualTo("REQUEST OK"));
                Assert.That(loggingMessages.Count, Is.EqualTo(3));
                Assert.That(loggingMessages[0], Is.EqualTo("[CLIENT] connecting to broker at tcp://localhost:5555"));
                Assert.That(loggingMessages[1].Contains("[CLIENT INFO] sending"), Is.True);
                Assert.That(loggingMessages[2].Contains("[CLIENT INFO] received"), Is.True);
            }
        }
示例#4
0
        /// <summary>
        /// Stops the proxy, blocking until the underlying <see cref="Poller"/> has completed.
        /// </summary>
        /// <exception cref="InvalidOperationException">The proxy has not been started.</exception>
        public void Stop()
        {
            if (Interlocked.CompareExchange(ref m_state, StateStopping, StateStarted) != StateStarted)
            {
                throw new InvalidOperationException("Proxy has not been started");
            }

            if (!m_externalPoller)
            {
                m_poller.CancelAndJoin();
                m_poller = null;
            }

            m_frontend.ReceiveReady -= OnFrontendReady;
            m_backend.ReceiveReady  -= OnBackendReady;

            m_state = StateStopped;
        }
示例#5
0
        public void Run()
        {
            Console.WriteLine("[CLIENT {0}] Starting", m_id);

            var rnd = new Random(m_id);
            // each request shall have an unique id in order to recognize an reply for a request
            var messageId = new byte[5];
            // create clientId for messages
            var clientId = new[] { m_id };
            // a flag to signal that an answer has arrived
            bool messageAnswered = false;
            // we use a poller because we have a socket and a timer to monitor
            using (var clientPoller = new Poller())
            using (var context = NetMQContext.Create())
            using (var client = context.CreateRequestSocket())
            using (var monitor = context.CreatePushSocket())
            {
                client.Connect(m_localFrontendAddress);
                monitor.Connect(m_monitorAddress);

                client.Options.Identity = new[] { m_id };
                var timer = new NetMQTimer((int)TimeSpan.FromSeconds(10).TotalMilliseconds);

                // use as flag to indicate exit
                var exit = false;

                // every 10 s check if message has been received, if not then send error message and ext
                // and restart timer otherwise
                timer.Elapsed += (s, e) =>
                {
                    if (messageAnswered)
                    {
                        e.Timer.Enable = true;
                    }
                    else
                    {
                        var msg = string.Format("[CLIENT {0}] ERR - EXIT - lost message {1}", m_id, messageId);
                        // send an error message
                        monitor.Send(msg);

                        // if poller is started than stop it
                        if (clientPoller.IsStarted)
                            clientPoller.CancelAndJoin();
                        // mark the required exit
                        exit = true;
                    }
                };

                // process arriving answers
                client.ReceiveReady += (s, e) =>
                {
                    // mark the arrival of an answer
                    messageAnswered = true;
                    // worker is supposed to answer with our request id
                    var reply = e.Socket.ReceiveMultipartMessage();

                    if (reply.FrameCount == 0)
                    {
                        // something went wrong
                        monitor.Send(string.Format("[CLIENT {0}] Received an empty message!", m_id));
                        // mark the exit flag to ensure the exit
                        exit = true;
                    }
                    else
                    {
                        var sb = new StringBuilder();

                        // create success message
                        foreach (var frame in reply)
                            sb.Append("[" + frame.ConvertToString() + "]");

                        // send the success message
                        monitor.Send(string.Format("[CLIENT {0}] Received answer {1}",
                            m_id,
                            sb.ToString()));
                    }
                };

                // add socket & timer to poller
                clientPoller.AddSocket(client);
                clientPoller.AddTimer(timer);

                // start poller in another thread to allow the continued processing
                clientPoller.PollTillCancelledNonBlocking();

                // if true the message has been answered
                // the 0th message is always answered
                messageAnswered = true;

                while (!exit)
                {
                    // simulate sporadic activity by randomly delaying
                    Thread.Sleep((int)TimeSpan.FromSeconds(rnd.Next(5)).TotalMilliseconds);

                    // only send next message if the previous one has been replied to
                    if (messageAnswered)
                    {
                        // generate random 5 byte as identity for for the message
                        rnd.NextBytes(messageId);

                        messageAnswered = false;

                        // create message [client adr][empty][message id] and send it
                        var msg = new NetMQMessage();

                        msg.Push(messageId);
                        msg.Push(NetMQFrame.Empty);
                        msg.Push(clientId);

                        client.SendMessage(msg);
                    }
                }

                // stop poller if needed
                if (clientPoller.IsStarted)
                    clientPoller.CancelAndJoin();
            }
        }
示例#6
0
        /// <summary>
        ///     the broker setting up the cluster
        /// 
        /// 
        ///          State 2 ---+         +--- State n
        ///                     |         |
        ///                     +----+----+
        ///     client 1 ---|        |         |--- worker 1
        ///     client 2 ---+---- BROKER 1 ----+--- worker 2
        ///     :           |        |         |    :
        ///     client n ---+   +----+----+    +--- worker n
        ///                     |         |
        ///                  BROKER 2   BROKER n
        /// 
        ///     BROKER 2 and n are not included and must be setup separately
        /// 
        ///     A minimum of two address must be supplied
        /// </summary>
        /// <param name="args">[0] = this broker's address
        ///                    [1] = 1st peer's address
        ///                     :
        ///                    [n] = nth peer address</param>
        /// <remarks>
        ///     since "inproc://" is not working in NetMQ we use "tcp://"
        ///     for each broker we need 5 ports which for this example are
        ///     assigned as follows (in true life it should be configurable whether 
        ///     they are ports or tcp/ip addresses)
        /// 
        ///     this brokers address => local frontend binds to     tcp://127.0.0.1:5555
        ///                             cloud frontend binds to                    :5556
        ///                             local backend binds to                     :5557
        ///                             state backend binds to                     :5558
        ///                             monitor PULL binds to                      :5559
        /// 
        ///     the sockets are connected as follows
        /// 
        ///               this broker's monitor PUSH connects to    tcp://127.0.0.1:5559
        /// 
        ///                         (if peer's address and port is  tcp://127.0.0.1:5575)
        ///             
        ///               this broker's cloud backend connects to                  :5576
        ///               this broker's state frontend connects to                 :5578
        /// 
        ///     this scheme is fix in this example
        /// </remarks>
        public static void Main(string[] args)
        {
            Console.Title = "NetMQ Inter-Broker Router";

            const string baseAddress = "tcp://127.0.0.1:";

            if (args.Length < 2)
            {
                Console.WriteLine("usage: program me peer1 [peer]*");
                Console.WriteLine("each broker needs 5 port for his sockets!");
                Console.WriteLine("place enough distance between multiple broker addresses!");
                Environment.Exit(-1);
            }

            // trapping Ctrl+C as exit signal!
            Console.CancelKeyPress += (s, e) =>
            {
                e.Cancel = true;
                s_keepRunning = false;
            };

            // get random generator for later use
            var rnd = new Random();
            // get list for registering the clients
            var clients = new List<byte[]>(NbrClients);
            // get a list of peer addresses
            var peers = new List<byte[]>();
            // get all peer addresses - first is this broker!
            for (var i = 1; i < args.Length; i++)
                peers.Add(Encoding.UTF8.GetBytes(args[i]));

            // build this broker's address
            var me = baseAddress + args[0];
            // get the port as integer for later use
            var myPort = int.Parse(args[0]);

            Console.WriteLine("[BROKER] The broker can be stopped by using CTRL+C!");
            Console.WriteLine("[BROKER] setting up sockets ...");

            // set up all the addresses needed in the due course
            var localFrontendAddress = me;
            var cloudFrontendAddress = baseAddress + (myPort + 1);
            var localBackendAddress = baseAddress + (myPort + 2);
            var stateBackendAddress = baseAddress + (myPort + 3);
            var monitorAddress = baseAddress + (myPort + 4);

            // create the context and all the sockets
            using (var context = NetMQContext.Create())
            using (var localFrontend = context.CreateRouterSocket())
            using (var localBackend = context.CreateRouterSocket())
            using (var cloudFrontend = context.CreateRouterSocket())
            using (var cloudBackend = context.CreateRouterSocket())
            using (var stateBackend = context.CreatePublisherSocket())
            using (var stateFrontend = context.CreateSubscriberSocket())
            using (var monitor = context.CreatePullSocket())
            {
                // give every socket an unique identity, e.g. LocalFrontend[Port]
                SetIdentities(myPort,
                    localFrontend,
                    cloudFrontend,
                    localBackend,
                    stateBackend,
                    monitor,
                    cloudBackend, stateFrontend);

                // subscribe to any message on the stateFrontend socket!
                stateFrontend.Subscribe("");

                // bind the serving sockets
                localFrontend.Bind(localFrontendAddress);
                cloudFrontend.Bind(cloudFrontendAddress);
                localBackend.Bind(localBackendAddress);
                stateBackend.Bind(stateBackendAddress);
                monitor.Bind(monitorAddress);

                // connect sockets to peers
                for (var i = 1; i < args.Length; i++)
                {
                    // build the cloud back end address
                    var peerPort = int.Parse(args[i]);
                    var address = baseAddress + (peerPort + 1);
                    Console.WriteLine("[BROKER] connect to cloud peer {0}", address);

                    // this cloudBackend connects to all peer cloudFrontends
                    cloudBackend.Connect(address);

                    // build the state front end address
                    address = baseAddress + (peerPort + 3);
                    Console.WriteLine("[BROKER] subscribe to state peer {0}", address);

                    // this stateFrontend to all peer stateBackends
                    stateFrontend.Connect(address);
                }

                // setup the local worker queue for LRU and monitor cloud capacity
                var workerQueue = new Queue<byte[]>();
                int previousLocalCapacity = 0;

                // receive the capacity available from other peer(s)
                stateFrontend.ReceiveReady += (s, e) =>
                {
                    // the message should contain the available cloud capacity
                    var capacity = e.Socket.ReceiveFrameString();

                    Debug.Assert(string.IsNullOrWhiteSpace(capacity), "StateFrontend: message was empty!");

                    int couldCapacity;
                    Debug.Assert(int.TryParse(capacity, out couldCapacity), "StateFrontend: message did not contain a number!");
                };

                // get the status message and print it
                monitor.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveFrameString();

                    Console.WriteLine("[MONITOR] {0}", msg);
                };

                // all local clients are connecting to this socket
                // they send a REQ and get a REPLY
                localFrontend.ReceiveReady += (s, e) =>
                {
                    // [client adr][empty][message id]
                    var request = e.Socket.ReceiveMultipartMessage();
                    // register the local client for later identification if not known
                    if (!clients.Any(n => AreSame(n, request[0])))
                        clients.Add(request[0].Buffer);
                    // if we have local capacity send worker else send to cloud
                    if (workerQueue.Count > 0)
                    {
                        // get the LRU worker adr
                        var worker = workerQueue.Dequeue();
                        // wrap message with workers address
                        var msg = Wrap(worker, request);
                        // send message to the worker
                        // [worker adr][empty][client adr][empty][data]
                        localBackend.SendMessage(msg);
                    }
                    else
                    {
                        // get an random index for peers
                        var peerIdx = rnd.Next(peers.Count - 2) + 2;
                        // get peers address
                        var peer = peers[peerIdx];
                        // wrap message with peer's address
                        var msg = Wrap(peer, request);
                        // [peer adr][empty][client adr][empty][data]
                        cloudBackend.SendMessage(msg);
                    }
                };

                // the workers are connected to this socket
                // we get a REPLY either for a cloud client [worker adr][empty][peer adr][empty][peer client adr][empty][data]
                // or local client [worker adr][empty][client adr][empty][data]
                // or a READY message [worker adr][empty][WORKER_READY]
                localBackend.ReceiveReady += (s, e) =>
                {
                    // a worker can send "READY" or a request
                    // or an REPLAY
                    var msg = e.Socket.ReceiveMultipartMessage();

                    // just to make sure we received a proper message
                    Debug.Assert(msg != null && msg.FrameCount > 0, "[LocalBackend] message was empty or frame count == 0!");

                    // get the workers identity
                    var id = Unwrap(msg);
                    // this worker done in either way so add it to available workers
                    workerQueue.Enqueue(id);
                    // if it is NOT a ready message we need to route the message
                    // it could be a reply to a peer or a local client
                    // [WORKER_READY] or [client adr][empty][data] or [peer adr][empty][peer client adr][empty][data]
                    if (msg[0].Buffer[0] != WorkerReady)
                    {
                        Debug.Assert(msg.FrameCount > 2, "[LocalBackend] None READY message malformed");

                        // if the adr (first frame) is any of the clients send the REPLY there
                        // and send it to the peer otherwise
                        if (clients.Any(n => AreSame(n, msg.First)))
                            localFrontend.SendMessage(msg);
                        else
                            cloudFrontend.SendMessage(msg);
                    }
                };

                // this socket is connected to all peers
                // we receive either a REQ or a REPLY form a peer
                // REQ [peer adr][empty][peer client adr][empty][message id] -> send to peer for processing
                // REP [peer adr][empty][client adr][empty][message id] -> send to local client
                cloudBackend.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage();

                    // just to make sure we received a message
                    Debug.Assert(msg != null && msg.FrameCount > 0, "[CloudBackend] message was empty or frame count == 0!");

                    // we need the peers address for proper addressing
                    var peerAdr = Unwrap(msg);

                    // the remaining message must be at least 3 frames!
                    Debug.Assert(msg.FrameCount > 2, "[CloudBackend] message malformed");

                    // if the id is any of the local clients it is a REPLY
                    // and a REQ otherwise
                    if (clients.Any(n => AreSame(n, msg.First)))
                    {
                        // [client adr][empty][message id]
                        localFrontend.SendMessage(msg);
                    }
                    else
                    {
                        // add the peers address to the request
                        var request = Wrap(peerAdr, msg);
                        // [peer adr][empty][peer client adr][empty][message id]
                        cloudFrontend.SendMessage(request);
                    }
                };

                // all peers are binding to this socket
                // we receive REPLY or REQ from peers
                // REQ [peer adr][empty][peer client adr][empty][data] -> send to local worker for processing
                // REP [peer adr][empty][client adr][empty][data] -> send to local client
                cloudFrontend.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage();

                    // just to make sure we received a message
                    Debug.Assert(msg != null && msg.FrameCount > 0, "[CloudFrontend] message was empty or frame count == 0!");

                    // we may need need the peers address for proper addressing
                    var peerAdr = Unwrap(msg);

                    // the remaining message must be at least 3 frames!
                    Debug.Assert(msg.FrameCount > 2, "[CloudFrontend] message malformed");

                    // if the address is any of the local clients it is a REPLY
                    // and a REQ otherwise
                    if (clients.Any(n => AreSame(n, msg.First)))
                        localFrontend.SendMessage(msg);
                    else
                    {
                        // in order to know which per to send back the peers adr must be added again
                        var original = Wrap(peerAdr, msg);

                        // reduce the capacity to reflect the use of a worker by a cloud request
                        previousLocalCapacity = workerQueue.Count;
                        // get the LRU worker
                        var workerAdr = workerQueue.Dequeue();
                        // wrap the message with the worker address and send
                        var request = Wrap(workerAdr, original);
                        localBackend.SendMessage(request);
                    }
                };

                // in order to reduce chatter we only check to see if we have local capacity to provide to cloud
                // periodically every 2 seconds with a timer
                var timer = new NetMQTimer((int)TimeSpan.FromSeconds(2).TotalMilliseconds);

                timer.Elapsed += (t, e) =>
                {
                    // send message only if the previous send information changed
                    if (previousLocalCapacity != workerQueue.Count)
                    {
                        // set the information
                        previousLocalCapacity = workerQueue.Count;
                        // generate the message
                        var msg = new NetMQMessage();
                        var data = new NetMQFrame(previousLocalCapacity.ToString());
                        msg.Append(data);
                        var stateMessage = Wrap(Encoding.UTF8.GetBytes(me), msg);
                        // publish info
                        stateBackend.SendMessage(stateMessage);
                    }

                    // restart the timer
                    e.Timer.Enable = true;
                };

                // start all clients and workers as threads
                var clientTasks = new Thread[NbrClients];
                var workerTasks = new Thread[NbrWorker];

                for (var i = 0; i < NbrClients; i++)
                {
                    var client = new Client(localFrontendAddress, monitorAddress, (byte)i);
                    clientTasks[i] = new Thread(client.Run) { Name = string.Format("Client_{0}", i) };
                    clientTasks[i].Start();
                }

                for (var i = 0; i < NbrWorker; i++)
                {
                    var worker = new Worker(localBackendAddress, (byte)i);
                    workerTasks[i] = new Thread(worker.Run) { Name = string.Format("Worker_{0}", i) };
                    workerTasks[i].Start();
                }

                var sockets = new NetMQSocket[]
                {
                    localFrontend,
                    localBackend,
                    cloudFrontend,
                    cloudBackend,
                    stateFrontend,
                    stateBackend,
                    monitor
                };

                // create poller and add sockets & timer
                var poller = new Poller(sockets);

                poller.AddTimer(timer);

                // start monitoring the sockets
                Task.Factory.StartNew(poller.PollTillCancelled);

                // we wait for a CTRL+C to exit
                while (s_keepRunning)
                {}

                Console.WriteLine("Ctrl-C encountered! Exiting the program!");

                if (poller.IsStarted)
                    poller.CancelAndJoin();

                poller.Dispose();
            }
        }
示例#7
0
        public void Send_EmptyReplyFromBrokerWithLogging_ShouldThrowApplicationException()
        {
            const string hostAddress = "tcp://localhost:5555";
            var loggingMessages = new List<string>();

            // setup the counter socket for communication
            using (var context = NetMQContext.Create())
            using (var broker = context.CreateRouterSocket())
            using (var poller = new Poller())
            using (var session = new MDPClient(hostAddress))
            {
                broker.Bind(hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    // return empty reply
                    var msg = e.Socket.ReceiveMessage();
                    // we expect to receive a 4 Frame message
                    // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"]
                    if (msg.FrameCount != 5)
                        Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount);
                    // REQUEST socket will strip the his address + empty frame
                    // ROUTER has to add the address prelude in order to identify the correct socket(!)
                    // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"]
                    e.Socket.SendMessage(msg);
                };

                poller.AddSocket(broker);
                Task.Factory.StartNew(poller.PollTillCancelled);

                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info);
                // well formed message
                var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") });
                // correct call
                session.Send("echo", requestMessage);

                poller.CancelAndJoin();
                poller.RemoveSocket(broker);

                Assert.That(loggingMessages.Count, Is.EqualTo(3));
                Assert.That(loggingMessages[0], Is.EqualTo("[CLIENT] connecting to broker at tcp://localhost:5555"));
                Assert.That(loggingMessages[1].Contains("[CLIENT INFO] sending"), Is.True);
                Assert.That(loggingMessages[2].Contains("[CLIENT INFO] received"), Is.True);
            }
        }
示例#8
0
        public void Send_WrongMDPVersionFromBrokerNoLogging_ShouldThrowApplicationException()
        {
            const string hostAddress = "tcp://localhost:5555";

            // setup the counter socket for communication
            using (var context = NetMQContext.Create())
            using (var broker = context.CreateRouterSocket())
            using (var poller = new Poller())
            using (var session = new MDPClient(hostAddress))
            {
                broker.Bind(hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    // return empty reply
                    var msg = e.Socket.ReceiveMessage();
                    // we expect to receive a 4 Frame message
                    // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"]
                    if (msg.FrameCount != 5)
                        Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount);
                    // REQUEST socket will strip the his address + empty frame
                    // ROUTER has to add the address prelude in order to identify the correct socket(!)
                    // [REQ ADR][EMPTY]["MDPC00"]["echo"]["REQUEST"]
                    var clientAddress = msg.Pop();
                    msg.Pop(); // forget empty frame
                    msg.Pop(); // drop the MDP Version Frame
                    msg.Push("MDPC00"); // insert wrong MDP version
                    msg.Push(NetMQFrame.Empty);
                    msg.Push(clientAddress); // reinsert the client's address

                    e.Socket.SendMessage(msg);
                };

                poller.AddSocket(broker);
                Task.Factory.StartNew(poller.PollTillCancelled);

                // well formed message
                var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") });

                try
                {
                    session.Send("echo", requestMessage);
                }
                catch (ApplicationException ex)
                {
                    Assert.That(ex.Message, Is.StringContaining("MDP Version mismatch"));
                }

                poller.CancelAndJoin();
                poller.RemoveSocket(broker);
            }
        }
示例#9
0
        public void Send_WrongServiceNameWithLogging_ShouldLogPermanentError()
        {
            const string hostAddress = "tcp://localhost:5555";
            var loggingMessages = new List<string>();

            // setup the counter socket for communication
            using (var context = NetMQContext.Create())
            using (var broker = context.CreateRouterSocket())
            using (var poller = new Poller())
            using (var session = new MDPClient(hostAddress))
            {
                broker.Bind(hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    // just swallow message -> wrong service name
                    e.Socket.ReceiveMessage();
                };

                poller.AddSocket(broker);
                Task.Factory.StartNew(poller.PollTillCancelled);

                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info);
                // well formed message
                var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") });
                // wrong service name
                session.Send("xyz", requestMessage);

                poller.CancelAndJoin();
                poller.RemoveSocket(broker);

                Assert.That(loggingMessages.Count, Is.EqualTo(7));
                Assert.That(loggingMessages[6], Is.EqualTo("[CLIENT ERROR] permanent error, abandoning!"));
            }
        }
示例#10
0
        public void Receive_RequestWithWrongMDPComand_ShouldLogCorrectMessage()
        {
            const string hostAddress = "tcp://localhost:5555";
            var loggingMessages = new List<string> ();
            var first = true;

            // setup the counter socket for communication
            using (var context = NetMQContext.Create ())
            using (var broker = context.CreateRouterSocket ())
            using (var poller = new Poller ())
            using (var session = new MDPWorker (hostAddress, "test", Encoding.ASCII.GetBytes ("Worker"), 2))
            {
                broker.Bind (hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage ();
                    // we expect to receive a 5 Frame message
                    // [WORKER ADR][EMPTY]["MDPW01"]["READY"]["test"]
                    if (msg.FrameCount != 5)
                        return; // it is a HEARTBEAT
                    // make sure the frames are as expected
                    Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty));
                    Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01"));
                    Assert.That (msg[3].BufferSize, Is.EqualTo (1));
                    Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Ready));
                    Assert.That (msg[4].ConvertToString (), Is.EqualTo ("test"));

                    // tell worker to stop gracefully
                    var reply = new NetMQMessage ();
                    if (first)
                    {
                        reply.Push (new[] { (byte) 0xff });
                        first = false;
                    }
                    else
                        reply.Push (new[] { (byte) MDPCommand.Kill });
                    // push MDP Version
                    reply.Push ("MDPW01");
                    // push separator
                    reply.Push (NetMQFrame.Empty);
                    // push worker address
                    reply.Push (msg[0]);
                    // send reply which is a request for the worker
                    e.Socket.SendMessage (reply);
                };
                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info);

                poller.AddSocket (broker);
                Task.Factory.StartNew (poller.PollTillCancelled);

                session.HeartbeatDelay = TimeSpan.FromMilliseconds (250);
                session.ReconnectDelay = TimeSpan.FromMilliseconds (250);
                // initialise the worker - broker protocol
                session.Receive (null);

                Assert.That (loggingMessages.Count (m => m.Contains ("[WORKER ERROR] invalid command received")), Is.EqualTo (1));
                Assert.That (loggingMessages.Count (m => m.Contains ("abandoning")), Is.EqualTo (1));

                poller.CancelAndJoin ();
                poller.RemoveSocket (broker);
            }
        }
示例#11
0
        public void ReceiveImplicitConnect_ValidScenario_ShouldReturnRequest()
        {
            const string hostAddress = "tcp://localhost:5557";
            var loggingMessages = new List<string> ();

            // setup the counter socket for communication
            using (var context = NetMQContext.Create ())
            using (var broker = context.CreateRouterSocket ())
            using (var poller = new Poller ())
            using (var session = new MDPWorker (hostAddress, "test", new[] { (byte) '1' }))
            {
                broker.Bind (hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage ();
                    // we expect to receive a 5 Frame message
                    // [WORKER ADR][EMPTY]["MDPW01"]["READY"]["test"]
                    if (msg.FrameCount != 5)
                        Assert.Fail ("Message with wrong count of frames {0}", msg.FrameCount);
                    // make sure the frames are as expected
                    Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty));
                    Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01"));
                    Assert.That (msg[3].BufferSize, Is.EqualTo (1));
                    Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Ready));
                    Assert.That (msg[4].ConvertToString (), Is.EqualTo ("test"));

                    // tell worker to stop gracefully
                    var reply = new NetMQMessage ();
                    reply.Push (new[] { (byte) MDPCommand.Kill });
                    // push MDP Version
                    reply.Push (msg[2]);
                    // push separator
                    reply.Push (NetMQFrame.Empty);
                    // push worker address
                    reply.Push (msg[0]);
                    // send reply which is a request for the worker
                    e.Socket.SendMessage (reply);
                };

                poller.AddSocket (broker);
                Task.Factory.StartNew (poller.PollTillCancelled);

                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info);
                // initialise the worker - broker protocol
                session.Receive (null);

                poller.CancelAndJoin ();
                poller.RemoveSocket (broker);

                Assert.That (loggingMessages.Count, Is.EqualTo (5));
                Assert.That (loggingMessages[0], Is.EqualTo ("[WORKER] connected to broker at tcp://localhost:5557"));
                Assert.That (loggingMessages[1].Contains ("[WORKER] sending"), Is.True);
                Assert.That (loggingMessages[2].Contains ("[WORKER] received"));
                Assert.That (loggingMessages[4].Contains ("abandoning"));
            }
        }
示例#12
0
        public void Receive_RequestWithWrongFirstFrame_ShouldThrowApplicationException()
        {
            const string hostAddress = "tcp://localhost:5555";

            // setup the counter socket for communication
            using (var context = NetMQContext.Create ())
            using (var broker = context.CreateRouterSocket ())
            using (var poller = new Poller ())
            using (var session = new MDPWorker (hostAddress, "test"))
            {
                broker.Bind (hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage ();
                    // we expect to receive a 5 Frame message
                    // [WORKER ADR][EMPTY]["MDPW01"]["READY"]["test"]
                    if (msg.FrameCount != 5)
                        Assert.Fail ("Message with wrong count of frames {0}", msg.FrameCount);
                    // make sure the frames are as expected
                    Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty));
                    Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01"));
                    Assert.That (msg[3].BufferSize, Is.EqualTo (1));
                    Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Ready));
                    Assert.That (msg[4].ConvertToString (), Is.EqualTo ("test"));

                    // tell worker to stop gracefully
                    var reply = new NetMQMessage ();
                    reply.Push (new[] { (byte) MDPCommand.Kill });
                    // push MDP Version
                    reply.Push ("MDPW01");
                    // push separator
                    reply.Push ("Should be empty");
                    // push worker address
                    reply.Push (msg[0]);
                    // send reply which is a request for the worker
                    e.Socket.SendMessage (reply);
                };

                poller.AddSocket (broker);
                Task.Factory.StartNew (poller.PollTillCancelled);

                try
                {
                    session.Receive (null);
                }
                catch (ApplicationException ex)
                {
                    Assert.That (ex.Message, Is.EqualTo ("First frame must be an empty frame!"));
                }

                poller.CancelAndJoin ();
                poller.RemoveSocket (broker);
            }
        }
示例#13
0
        public void Receive_REPLYtoREQUEST_ShouldSendCorrectReply()
        {
            const string hostAddress = "tcp://localhost:5557";
            var loggingMessages = new List<string> ();

            // setup the counter socket for communication
            using (var context = NetMQContext.Create ())
            using (var broker = context.CreateRouterSocket ())
            using (var poller = new Poller ())
            using (var session = new MDPWorker (hostAddress, "test", new[] { (byte) 'W', (byte) '1' }))
            {
                broker.Bind (hostAddress);
                // we need to pick up any message in order to avoid errors
                broker.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage ();
                    if (msg[3].Buffer[0] == (byte) MDPCommand.Ready)
                    {
                        // this is a READY message and we
                        // send REQUEST message
                        var request = new NetMQMessage ();
                        request.Push ("echo test"); // [request]
                        request.Push (NetMQFrame.Empty); // [e][request]
                        request.Push ("C1"); // [client adr][e][request]
                        request.Push (new[] { (byte) MDPCommand.Request }); // [command][client adr][e][request]
                        request.Push (msg[2]); // [header][command][client adr][e][request]
                        request.Push (NetMQFrame.Empty); // [e][header][command][client adr][e][request]
                        request.Push (msg[0]); // [worker adr][e][header][command][client adr][e][request]
                        // send reply which is a request for the worker
                        e.Socket.SendMessage (request);
                    }

                    if (msg[3].Buffer[0] == (byte) MDPCommand.Reply)
                    {
                        // we expect to receive
                        // [WORKER ADR][e]["MDPW01"][REPLY][CLIENT ADR][e][request == "echo test"]
                        // make sure the frames are as expected
                        Assert.That (msg[0].ConvertToString (), Is.EqualTo ("W1"));
                        Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty));
                        Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01"));
                        Assert.That (msg[3].BufferSize, Is.EqualTo (1));
                        Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Reply));
                        Assert.That (msg[4].ConvertToString (), Is.EqualTo ("C1"));
                        Assert.That (msg[5], Is.EqualTo (NetMQFrame.Empty));
                        Assert.That (msg[6].ConvertToString (), Is.EqualTo ("echo test"));

                        // tell worker to stop gracefully
                        var reply = new NetMQMessage ();
                        reply.Push (new[] { (byte) MDPCommand.Kill });
                        // push MDP Version
                        reply.Push (msg[2]);
                        // push separator
                        reply.Push (NetMQFrame.Empty);
                        // push worker address
                        reply.Push (msg[0]);
                        // send reply which is a request for the worker
                        e.Socket.SendMessage (reply);
                    }
                };

                poller.AddSocket (broker);
                Task.Factory.StartNew (poller.PollTillCancelled);

                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info);
                // initialise the worker - broker protocol
                // and get initial request
                var workerRequest = session.Receive (null);
                // just echo the request
                session.Receive (workerRequest);

                poller.CancelAndJoin ();
                poller.RemoveSocket (broker);

                Assert.That (loggingMessages.Count, Is.EqualTo (8));
                Assert.That (loggingMessages[0], Is.EqualTo ("[WORKER] connected to broker at tcp://localhost:5557"));
                Assert.That (loggingMessages[1].Contains ("Ready"));
                Assert.That (loggingMessages[2].Contains ("[WORKER] received"));
                Assert.That (loggingMessages[3].Contains ("Request"));
                Assert.That (loggingMessages[4].Contains ("Reply"));
                Assert.That (loggingMessages[6].Contains ("Kill"));
                Assert.That (loggingMessages[7].Contains ("abandoning"));
            }
        }
示例#14
0
        public void Receive_BrokerDisconnectedWithLogging_ShouldReturnRequest()
        {
            const string hostAddress = "tcp://localhost:5555";
            var loggingMessages = new List<string> ();

            // setup the counter socket for communication
            using (var context = NetMQContext.Create ())
            using (var broker = context.CreateRouterSocket ())
            using (var poller = new Poller ())
            using (var session = new MDPWorker (hostAddress, "test"))
            {
                broker.Bind (hostAddress);
                // we need to pick up any message in order to avoid errors but don't answer
                broker.ReceiveReady += (s, e) => e.Socket.ReceiveMultipartMessage ();

                poller.AddSocket (broker);
                Task.Factory.StartNew (poller.PollTillCancelled);

                // speed up the test
                session.HeartbeatDelay = TimeSpan.FromMilliseconds (250);
                session.ReconnectDelay = TimeSpan.FromMilliseconds (250);
                // set the event handler to receive the logging messages
                session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info);
                // initialise the worker - broker protocol
                session.Receive (null);

                poller.CancelAndJoin ();
                poller.RemoveSocket (broker);

                Assert.That (loggingMessages.Count (m => m.Contains ("retrying")), Is.EqualTo (3));
                // 3 times retrying and 1 time initial connecting
                Assert.That (loggingMessages.Count (m => m.Contains ("localhost")), Is.EqualTo (4));
                Assert.That (loggingMessages.Last ().Contains ("abandoning"));
            }
        }
示例#15
0
 public void Stop()
 {
     m_poller.CancelAndJoin();
 }
示例#16
0
        /// <summary>
        /// ParanoidPirate.Queue [-v]
        /// 
        /// Does load-balancing with heartbeating on worker tasks to detect
        /// crashed, blocked or slow running worker tasks    .
        /// </summary>
        private static void Main(string[] args)
        {
            Console.Title = "NetMQ ParanoidPirate Queue";

            // serves as flag for exiting the program
            var exit = false;
            // catch CTRL+C as exit command
            Console.CancelKeyPress += (s, e) =>
            {
                e.Cancel = true;
                exit = true;
            };

            var verbose = args.Length > 0 && args[0] == "-v";

            using (var context = NetMQContext.Create())
            using (var frontend = context.CreateRouterSocket())
            using (var backend = context.CreateRouterSocket())
            using (var poller = new Poller())
            {
                frontend.Bind(Commons.QueueFrontend);
                backend.Bind(Commons.QueueBackend);

                var workers = new Workers();

                // client sends to this socket
                frontend.ReceiveReady += (s, e) =>
                {
                    // only process incoming client requests
                    // if we have workers available handle client requests as long as we have workers
                    // storage capability of the socket otherwise and pick up later
                    if (workers.Available)
                    {
                        // get all message frames!
                        var request = frontend.ReceiveMultipartMessage();

                        if (verbose)
                            Console.WriteLine("[QUEUE] received {0}", request);

                        // get next available worker
                        var worker = workers.Next();
                        // wrap message with worker's address
                        var msg = Wrap(worker, request);

                        if (verbose)
                            Console.WriteLine("[QUEUE -> WORKER] sending {0}", msg);

                        backend.SendMessage(msg);
                    }
                };

                // worker sends to this socket
                backend.ReceiveReady += (s, e) =>
                {
                    var msg = e.Socket.ReceiveMultipartMessage();

                    if (verbose)
                        Console.WriteLine("[QUEUE <- WORKER] received {0}", msg);

                    // use workers identity for load-balancing
                    var workerIdentity = Unwrap(msg);
                    var worker = new Worker(workerIdentity);
                    workers.Ready(worker);
                    // just convenience
                    var readableWorkerId = workerIdentity.ConvertToString();

                    if (msg.FrameCount == 1)
                    {
                        var data = msg[0].ConvertToString();
                        // the message is either READY or HEARTBEAT or corrupted
                        switch (data)
                        {
                            case Commons.PPPHeartbeat:
                                Console.WriteLine("[QUEUE <- WORKER] Received a Heartbeat from {0}",
                                    readableWorkerId);
                                break;
                            case Commons.PPPReady:
                                Console.WriteLine("[QUEUE <- WORKER] Received a READY form {0}",
                                    readableWorkerId);
                                break;
                            default:
                                Console.WriteLine("[QUEUE <- WORKER] ERROR received an invalid message!");
                                break;
                        }
                    }
                    else
                    {
                        if (verbose)
                            Console.WriteLine("[QUEUE -> CLIENT] sending {0}", msg);

                        frontend.SendMessage(msg);
                    }
                };

                var timer = new NetMQTimer(Commons.HeartbeatInterval);
                // every specified ms QUEUE shall send a heartbeat to all connected workers
                timer.Elapsed += (s, e) =>
                {
                    // send heartbeat to every worker
                    foreach (var worker in workers)
                    {
                        var heartbeat = new NetMQMessage();

                        heartbeat.Push(new NetMQFrame(Commons.PPPHeartbeat));
                        heartbeat.Push(worker.Identity);

                        Console.WriteLine("[QUEUE -> WORKER] sending heartbeat!");

                        backend.SendMessage(heartbeat);
                    }
                    // restart timer
                    e.Timer.Enable = true;
                    // remove all dead or expired workers
                    workers.Purge();
                };

                if (verbose)
                    Console.WriteLine("[QUEUE] Start listening!");

                poller.AddSocket(frontend);
                poller.AddSocket(backend);

                poller.PollTillCancelledNonBlocking();

                // hit CRTL+C to stop the while loop
                while (!exit)
                {}

                // Cleanup
                poller.RemoveTimer(timer);
                // stop the poler task
                poller.CancelAndJoin();
                // remove the sockets - Dispose is called automatically
                poller.RemoveSocket(frontend);
                poller.RemoveSocket(backend);
            }
        }