public void MonitorDisposeProperlyWhenDisposedAfterMonitoredTcpSocket() { // The bug: // Given we monitor a netmq tcp socket // Given we disposed of the monitored socket first // When we dispose of the monitor // Then our monitor is Faulted with a EndpointNotFoundException // And monitor can't be stopped or disposed using (var context = NetMQContext.Create()) using (var res = context.CreateResponseSocket()) { NetMQMonitor monitor; using (var req = context.CreateRequestSocket()) { monitor = new NetMQMonitor(context, req, "inproc://#monitor", SocketEvents.All); Task.Factory.StartNew(monitor.Start); // Bug only occurs when monitoring a tcp socket var port = res.BindRandomPort("tcp://127.0.0.1"); req.Connect("tcp://127.0.0.1:" + port); req.Send("question"); Assert.That(res.ReceiveFrameString(), Is.EqualTo("question")); res.Send("response"); Assert.That(req.ReceiveFrameString(), Is.EqualTo("response")); } Thread.Sleep(100); // Monitor.Dispose should complete var completed = Task.Factory.StartNew(() => monitor.Dispose()).Wait(1000); Assert.That(completed, Is.True); } // NOTE If this test fails, it will hang because context.Dispose will block }
public void MonitorDisposeProperlyWhenDisposedAfterMonitoredTcpSocket() { // The bug: // Given we monitor a netmq tcp socket // Given we disposed of the monitored socket first // When we dispose of the monitor // Then our monitor is Faulted with a EndpointNotFoundException // And monitor can't be stopped or disposed using (var theContext = NetMQContext.Create()) using (var resSocket = theContext.CreateResponseSocket()) { NetMQMonitor monitor; using (var reqSocket = theContext.CreateRequestSocket()) { monitor = new NetMQMonitor(theContext, reqSocket, "inproc://#monitor", SocketEvent.All); Task.Factory.StartNew(() => monitor.Start()); //The bug is only occurring when monitor a tcp socket var port = resSocket.BindRandomPort("tcp://127.0.0.1"); reqSocket.Connect("tcp://127.0.0.1:" + port); reqSocket.Send("question"); Assert.That(resSocket.ReceiveString(), Is.EqualTo("question")); resSocket.Send("response"); Assert.That(reqSocket.ReceiveString(), Is.EqualTo("response")); } Thread.Sleep(100); // Monitor.Dispose should complete var completed = Task.Factory.StartNew(() => monitor.Dispose()).Wait(1000); Assert.That(completed, Is.True); } //Note: If this test fails, it will hang because the context Dispose will block }
private void DisposeMonitor() { _monitor.Connected -= Monitor_Connected; _monitor.Disconnected -= Monitor_Disconnected; _monitor.ConnectRetried -= Monitor_ConnectRetried; _monitor.Dispose(); _monitor = null; }
public void MonitorDisposeProperlyWhenDisposedAfterMonitoredTcpSocket() { // The bug: // Given we monitor a netmq tcp socket // Given we disposed of the monitored socket first // When we dipose of the monitor // Then our monitor is Faulted with a EndpointNotFoundException // And monitor can't be stopped or disposed Task monitorTask; using (var theContext = NetMQContext.Create()) using (var resSocket = theContext.CreateResponseSocket()) { NetMQMonitor monitor = null; using (var reqSocket = theContext.CreateRequestSocket()) { monitor = new NetMQMonitor(theContext, reqSocket, "inproc://#monitor", SocketEvent.All); monitorTask = Task.Factory.StartNew(() => monitor.Start()); //The bug is only occuring when monitor a tcp socket resSocket.Bind("tcp://127.0.0.1:12345"); reqSocket.Connect("tcp://127.0.0.1:12345"); reqSocket.Send("question"); Assert.That(resSocket.ReceiveString(), Is.EqualTo("question")); resSocket.Send("response"); Assert.That(reqSocket.ReceiveString(), Is.EqualTo("response")); } Thread.Sleep(100); // Monitor.Dispose should complete var completed = Task.Factory.StartNew(() => monitor.Dispose()).Wait(1000); Assert.That(completed, Is.True); } //Note: If this test fails, it will hang because the context Dispose will block }
public void Dispose() { _monitor?.Dispose(); _monitorTask?.Wait(1000); }
void IShimHandler.Run(PairSocket shim) { _poller = new NetMQPoller(); // Listen to actor dispose _ = Observable.FromEventPattern <NetMQSocketEventArgs>(e => shim.ReceiveReady += e, e => shim.ReceiveReady -= e) .Select(e => e.EventArgs) .ObserveOn(Scheduler.CurrentThread) .Subscribe(OnShimReady); _poller.Add(shim); _subscriberSocket = new SubscriberSocket(); _subscriberSocket.Options.ReceiveHighWatermark = 1000; _subscriberSocket.Options.Linger = TimeSpan.FromSeconds(2); _subscriberSocket.Options.TcpKeepalive = true; _subscriberSocket.Options.TcpKeepaliveIdle = TimeSpan.FromSeconds(5); _subscriberSocket.Options.TcpKeepaliveInterval = TimeSpan.FromSeconds(1); #if MONITOR var monitor = new NetMQMonitor(_subscriberSocket, "inproc://#monitor", SocketEvents.All); _ = Observable.FromEventPattern <NetMQMonitorSocketEventArgs>(monitor, "Connected") .Select(e => new { Event = "Connected", e }) .Merge(Observable.FromEventPattern <NetMQMonitorSocketEventArgs>(monitor, nameof(monitor.Listening)).Select(e => new { Event = "Listening", e })) .Merge(Observable.FromEventPattern <NetMQMonitorSocketEventArgs>(monitor, nameof(monitor.Accepted)).Select(e => new { Event = "Accepted", e })) .Merge(Observable.FromEventPattern <NetMQMonitorSocketEventArgs>(monitor, nameof(monitor.Closed)).Select(e => new { Event = "Closed", e })) .Merge(Observable.FromEventPattern <NetMQMonitorSocketEventArgs>(monitor, nameof(monitor.Disconnected)).Select(e => new { Event = "Disconnected", e })) .Do(e => _logger.Info("Monitor socket: {0}, {1}", e.Event, e.e.EventArgs.Address)) .Subscribe(); _ = Observable.FromEventPattern <NetMQMonitorErrorEventArgs>(monitor, nameof(monitor.AcceptFailed)) .Merge(Observable.FromEventPattern <NetMQMonitorErrorEventArgs>(monitor, nameof(monitor.ConnectDelayed))) .Merge(Observable.FromEventPattern <NetMQMonitorErrorEventArgs>(monitor, nameof(monitor.CloseFailed))) .Merge(Observable.FromEventPattern <NetMQMonitorErrorEventArgs>(monitor, nameof(monitor.BindFailed))) .Do(e => _logger.Error("Monitor error socket: {0}, {1}", e.EventArgs.ErrorCode, e.EventArgs.Address)) .Subscribe(); _ = Observable.FromEventPattern <NetMQMonitorIntervalEventArgs>(monitor, nameof(monitor.ConnectRetried)) .Do(e => _logger.Info("Monitor retry socket: {0}, {1}", e.EventArgs.Interval, e.EventArgs.Address)) .Subscribe(); monitor.AttachToPoller(_poller); #endif _ = Observable.FromEventPattern <NetMQSocketEventArgs>( e => _subscriberSocket.ReceiveReady += e, e => _subscriberSocket.ReceiveReady -= e) .Select(e => e.EventArgs) .ObserveOn(Scheduler.CurrentThread) .Subscribe(ReceivedMessage); _poller.Add(_subscriberSocket); _subscriberSocket.Connect($"tcp://{_address}:{_port + 1}"); shim.SignalOK(); try { _poller.Run(); } catch (Exception ex) { _logger.Fatal(ex, "Fatal error on NetMQ poller."); } // Cleanup stuff after stopping _poller.Remove(_subscriberSocket); _poller.Remove(shim); #if MONITOR if (monitor != null) { monitor.DetachFromPoller(); monitor.Dispose(); monitor = null; } #endif _poller.Dispose(); }