Exemple #1
0
        public void OnError(Exception exception)
        {
            InitializePublisherOnFirstUse();

            var exceptionWrapper = new SerializableException(exception);

            byte[] serializedException = exceptionWrapper.SerializeException();
            string exceptionAsString   = exception.ToString();

            m_publisherSocket.SendMoreFrame(QueueName)
            .SendMoreFrame("E")                                   // "N", "E" or "C" for "OnNext", "OnError" or "OnCompleted".
            .SendMoreFrame(exceptionAsString.SerializeProtoBuf()) // Human readable exception. Added for 100%
            // cross-platform debugging, so we can read
            // the error on the wire.
            .SendFrame(serializedException);                             // Machine readable exception. So we can pass the full exception to
            // the .NET client.

            // Comment in the remaining code for the standard pub/sub pattern.

            //if (this.HasObservers == false)
            //{
            //throw new QxNoSubscribers("Error E28244. As there are no subscribers to this publisher, this published exception will be lost.");
            //}

            //lock (_subscribersLock)
            //{
            //this._subscribers.ForEach(msg => msg.OnError(exception));
            //}
        }
Exemple #2
0
        public static SerializableException DeSerializeException(this byte[] bytes)
        {
            // Round-trip the exception: Serialize and de-serialize with a BinaryFormatter.
            var bf = new BinaryFormatter();

            using (var ms = new MemoryStream(bytes))
            {
                ms.Seek(0, 0);                 // Good practice.

                // Replace the original exception with de-serialized one
                SerializableException ex = (SerializableException)bf.Deserialize(ms);
                return(ex);
            }
        }
Exemple #3
0
        public static byte[] SerializeException(this SerializableException exception)
        {
            // Round-trip the exception: Serialize and de-serialize with a BinaryFormatter.
            var bf = new BinaryFormatter();

            using (var ms = new MemoryStream())
            {
                // "Save" object state
                bf.Serialize(ms, exception);

                ms.Seek(0, 0);                 // Good practice.

                return(ms.ToArray());
            }
        }
Exemple #4
0
        private void InitializeSubscriberOnFirstUse()
        {
            if (m_initializeSubscriberDone == false)             // Double checked locking.
            {
                lock (m_subscribersLock)
                {
                    if (m_initializeSubscriberDone == false)
                    {
                        Console.WriteLine("Subscriber socket connecting to: {0}", ZeroMqAddress);
                        m_subscriberSocket = new SubscriberSocket();

                        // Corner case: wait until subscriber socket is ready (see code below that waits for
                        // "_subscriberReadySignal").
                        NetMQMonitor monitor;
                        {
                            // Must ensure that we have a unique monitor name for every instance of this class.
                            string endpoint = string.Format("inproc://#SubjectNetMQ#Subscriber#{0}#{1}", this.QueueName, this.ZeroMqAddress);

                            monitor = new NetMQMonitor(m_subscriberSocket, endpoint,
                                                       SocketEvents.ConnectRetried | SocketEvents.Connected);
                            monitor.ConnectRetried += Subscriber_Event_ConnectRetried;
                            monitor.Connected      += Subscriber_Event_Connected;
                            monitor.StartAsync();
                        }

                        m_subscriberSocket.Options.ReceiveHighWatermark = 2000 * 1000;
                        m_subscriberSocket.Connect(this.ZeroMqAddress);
                        m_subscriberSocket.Subscribe(this.QueueName);

                        if (m_cancellationTokenSource == null)
                        {
                            m_cancellationTokenSource = new CancellationTokenSource();
                        }

                        ManualResetEvent threadReadySignal = new ManualResetEvent(false);

                        m_thread = new Thread(() =>
                        {
                            try
                            {
                                Console.Write("Thread initialized.\n");
                                threadReadySignal.Set();
                                while (m_cancellationTokenSource.IsCancellationRequested == false)
                                {
                                    string messageTopicReceived = m_subscriberSocket.ReceiveFrameString();
                                    if (messageTopicReceived != QueueName)
                                    {
                                        throw new Exception(string.Format("Error E65724. We should always subscribe on the queue name '{0}', instead we got '{1}'.", QueueName, messageTopicReceived));
                                    }
                                    var type = m_subscriberSocket.ReceiveFrameString();
                                    switch (type)
                                    {
                                    // Originated from "OnNext".
                                    case "N":
                                        T messageReceived = m_subscriberSocket.ReceiveFrameBytes().DeserializeProtoBuf <T>();
                                        lock (m_subscribersLock)
                                        {
                                            m_subscribers.ForEach(o => o.OnNext(messageReceived));
                                        }
                                        break;

                                    // Originated from "OnCompleted".
                                    case "C":
                                        lock (m_subscribersLock)
                                        {
                                            m_subscribers.ForEach(o => o.OnCompleted());

                                            // We are done! We don't want to send any more messages to subscribers, and we
                                            // want to close the listening socket.
                                            m_cancellationTokenSource.Cancel();
                                        }
                                        break;

                                    // Originated from "OnException".
                                    case "E":
                                        Exception exception;
                                        string exceptionAsString = "Uninitialized.";
                                        try
                                        {
                                            // Not used, but useful for cross-platform debugging: we can read the error straight off the wire.
                                            exceptionAsString = m_subscriberSocket.ReceiveFrameBytes().DeserializeProtoBuf <string>();
                                            SerializableException exceptionWrapper = m_subscriberSocket.ReceiveFrameBytes().DeSerializeException();
                                            exception = exceptionWrapper.InnerException;
                                        }
                                        catch (Exception ex)
                                        {
                                            // If we had trouble deserializing the exception (probably due to a
                                            // different version of .NET), then do the next best thing: (1) The
                                            // inner exception is the error we got when deserializing, and (2) the
                                            // main exception is the human-readable "exception.ToString()" that we
                                            // originally captured.
                                            exception = new Exception(exceptionAsString, ex);
                                        }

                                        lock (m_subscribersLock)
                                        {
                                            m_subscribers.ForEach(o => o.OnError(exception));
                                        }
                                        break;

                                    // Originated from a "Ping" request.
                                    case "P":
                                        // Do nothing, this is a ping command used to wait until sockets are initialized properly.
                                        Console.Write("Received ping.\n");
                                        break;

                                    default:
                                        throw new Exception(string.Format("Error E28734. Something is wrong - received '{0}' when we expected \"N\", \"C\" or \"E\" - are we out of sync?", type));
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.Write("Error E23844. Exception in threadName \"{0}\". Thread exiting. Exception: \"{1}\".\n", QueueName, ex.Message);
                                lock (m_subscribersLock)
                                {
                                    this.m_subscribers.ForEach((ob) => ob.OnError(ex));
                                }
                            }
                            finally
                            {
                                lock (m_subscribersLock)
                                {
                                    m_subscribers.Clear();
                                }
                                m_cancellationTokenSource.Dispose();

                                // Disconnect from the socket.
                                m_subscriberSocket.Dispose();
                            }
                        })
                        {
                            Name         = this.QueueName,
                            IsBackground = true                             // Have to set it to background, or else it will not exit when the program exits.
                        };
                        m_thread.Start();

                        // Wait for thread to properly spin up.
                        threadReadySignal.WaitOne(TimeSpan.FromMilliseconds(3000));

                        // Corner case: wait until the publisher socket is ready (see code above that sets
                        // "_subscriberReadySignal").
                        {
                            Stopwatch sw = Stopwatch.StartNew();
                            m_subscriberReadySignal.WaitOne(TimeSpan.FromMilliseconds(3000));
                            Console.Write("Subscriber: Waited {0} ms for connection.\n", sw.ElapsedMilliseconds);

                            monitor.ConnectRetried -= Subscriber_Event_ConnectRetried;
                            monitor.Connected      -= Subscriber_Event_Connected;

                            // Issue with NetMQ - cannot .Stop or .Dispose, or else it will dispose of the parent socket.
                            //monitor.Stop();
                            //monitor.Dispose();
                        }

                        Console.Write("Subscriber: finished setup.\n");

                        m_initializeSubscriberDone = true;
                    }
                }                  // lock
                Thread.Sleep(500); // Otherwise, the first item we subscribe  to may get missed by the subscriber.
            }
        }
Exemple #5
0
        private void InitializeSubscriberOnFirstUse(string addressZeroMq)
        {
            if (_initializeSubscriberDone == false)             // Double checked locking.
            {
                lock (_subscribersLock)
                {
                    if (_initializeSubscriberDone == false)
                    {
                        if (_cancellationTokenSource == null)
                        {
                            _cancellationTokenSource = new CancellationTokenSource();
                        }

                        _subscriberSocket = NetMqTransportShared.Instance(_loggerDelegate).GetSharedSubscriberSocket(addressZeroMq);

                        ManualResetEvent threadReadySignal = new ManualResetEvent(false);

                        _thread = new Thread(() =>
                        {
                            try
                            {
                                _loggerDelegate?.Invoke(string.Format("Thread initialized.\n"));
                                threadReadySignal.Set();
                                while (_cancellationTokenSource.IsCancellationRequested == false)
                                {
                                    //_loggerDelegate?.Invoke(string.Format("Received message for {0}.\n", typeof(T)));

                                    string messageTopicReceived = _subscriberSocket.ReceiveFrameString();
                                    if (messageTopicReceived != SubscriberFilterName)
                                    {
                                        // This message is for another subscriber. This should never occur.
#if DEBUG
                                        throw new Exception("Error E38444. Internal exception, this should never occur, as the ZeroMQ lib automaticlaly filters by subject name.");
#else
                                        return;
#endif
                                    }
                                    var type = _subscriberSocket.ReceiveFrameString();
                                    switch (type)
                                    {
                                    // Originated from "OnNext".
                                    case "N":
                                        T messageReceived = _subscriberSocket.ReceiveFrameBytes().DeserializeProtoBuf <T>();
                                        lock (_subscribersLock)
                                        {
                                            _subscribers.ForEach(o => o.OnNext(messageReceived));
                                        }
                                        break;

                                    // Originated from "OnCompleted".
                                    case "C":
                                        lock (_subscribersLock)
                                        {
                                            _subscribers.ForEach(o => o.OnCompleted());

                                            // We are done! We don't want to send any more messages to subscribers, and we
                                            // want to close the listening socket.
                                            _cancellationTokenSource.Cancel();
                                        }
                                        break;

                                    // Originated from "OnException".
                                    case "E":
                                        Exception exception;
                                        string exceptionAsString = "Uninitialized.";
                                        try
                                        {
                                            // Not used, but useful for cross-platform debugging: we can read the error straight off the wire.
                                            exceptionAsString = _subscriberSocket.ReceiveFrameBytes().DeserializeProtoBuf <string>();
                                            SerializableException exceptionWrapper = _subscriberSocket.ReceiveFrameBytes().DeSerializeException();
                                            exception = exceptionWrapper.InnerException;
                                        }
                                        catch (Exception ex)
                                        {
                                            // If we had trouble deserializing the exception (probably due to a
                                            // different version of .NET), then do the next best thing: (1) The
                                            // inner exception is the error we got when deserializing, and (2) the
                                            // main exception is the human-readable "exception.ToString()" that we
                                            // originally captured.
                                            exception = new Exception(exceptionAsString, ex);
                                        }

                                        lock (_subscribersLock)
                                        {
                                            _subscribers.ForEach(o => o.OnError(exception));
                                        }
                                        break;

                                    // Originated from a "Ping" request.
                                    case "P":
                                        // Do nothing, this is a ping command used to wait until sockets are initialized properly.
                                        _loggerDelegate?.Invoke(string.Format("Received ping.\n"));
                                        break;

                                    default:
                                        throw new Exception(string.Format("Error E28734. Something is wrong - received '{0}' when we expected \"N\", \"C\" or \"E\" - are we out of sync?", type));
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                _loggerDelegate?.Invoke(string.Format("Error E23844. Exception in threadName \"{0}\". Thread exiting. Exception: \"{1}\".\n", SubscriberFilterName, ex.Message));
                                lock (_subscribersLock)
                                {
                                    this._subscribers.ForEach((ob) => ob.OnError(ex));
                                }
                            }
                            finally
                            {
                                lock (_subscribersLock)
                                {
                                    _subscribers.Clear();
                                }
                                _cancellationTokenSource.Dispose();

                                // Disconnect from the socket.
                                _subscriberSocket.Dispose();
                            }
                        })
                        {
                            Name         = this.SubscriberFilterName,
                            IsBackground = true                             // Have to set it to background, or else it will not exit when the program exits.
                        };
                        _thread.Start();

                        // Wait for subscriber thread to properly spin up.
                        threadReadySignal.WaitOne(TimeSpan.FromMilliseconds(3000));

                        // Intent: Now connect to the socket.
                        {
                            _loggerDelegate?.Invoke(string.Format("Subscriber socket connecting to: {0}\n", addressZeroMq));

                            // this.SubscriberFilterName is set to the type T of the incoming class by default, so we can
                            // have many types on the same transport.
                            _subscriberSocket.Subscribe(this.SubscriberFilterName);
                        }

                        _loggerDelegate?.Invoke(string.Format("Subscriber: finished setup.\n"));

                        _initializeSubscriberDone = true;
                    }
                }                  // lock
                Thread.Sleep(500); // Otherwise, the first item we subscribe  to may get missed by the subscriber.
            }
        }