public void Oneway(Command command) { Exception error = null; lock (reconnectMutex) { if (IsShutdownCommand(command) && ConnectedTransport == null) { if (command.IsShutdownInfo) { // Skipping send of ShutdownInfo command when not connected. return; } if (command.IsRemoveInfo) { // Simulate response to RemoveInfo command Response response = new Response(); response.CorrelationId = command.CommandId; OnCommand(this, response); return; } } // Keep trying until the message is sent. for (int i = 0; !disposed; i++) { try { // Wait for transport to be connected. ITransport transport = ConnectedTransport; DateTime start = DateTime.Now; bool timedout = false; while (transport == null && !disposed && connectionFailure == null) { int elapsed = (int)(DateTime.Now - start).TotalMilliseconds; if (this.timeout > 0 && elapsed > timeout) { timedout = true; Tracer.DebugFormat("FailoverTransport.oneway - timed out after {0} mills", elapsed); break; } // Release so that the reconnect task can run try { // This is a bit of a hack, what should be happening is that when // there's a reconnect the reconnectTask should signal the Monitor // or some other event object to indicate that we can wakeup right // away here, instead of performing the full wait. Monitor.Exit(reconnectMutex); Thread.Sleep(100); Monitor.Enter(reconnectMutex); } catch (Exception e) { Tracer.DebugFormat("Interrupted: {0}", e.Message); } transport = ConnectedTransport; } if (transport == null) { // Previous loop may have exited due to use being disposed. if (disposed) { error = new IOException("Transport disposed."); } else if (connectionFailure != null) { error = connectionFailure; } else if (timedout) { error = new IOException("Failover oneway timed out after " + timeout + " milliseconds."); } else { error = new IOException("Unexpected failure."); } break; } // If it was a request and it was not being tracked by // the state tracker, then hold it in the requestMap so // that we can replay it later. Tracked tracked = stateTracker.track(command); lock (((ICollection)requestMap).SyncRoot) { if (tracked != null && tracked.WaitingForResponse) { requestMap.Add(command.CommandId, tracked); } else if (tracked == null && command.ResponseRequired) { requestMap.Add(command.CommandId, command); } } // Send the message. try { transport.Oneway(command); stateTracker.trackBack(command); } catch (Exception e) { // If the command was not tracked.. we will retry in // this method if (tracked == null) { // since we will retry in this method.. take it // out of the request map so that it is not // sent 2 times on recovery if (command.ResponseRequired) { lock (((ICollection)requestMap).SyncRoot) { requestMap.Remove(command.CommandId); } } // Rethrow the exception so it will handled by // the outer catch throw e; } } return; } catch (Exception e) { Tracer.DebugFormat("Send Oneway attempt: {0} failed: Message = {1}", i, e.Message); Tracer.DebugFormat("Failed Message Was: {0}", command); HandleTransportFailure(e); } } } if (!disposed) { if (error != null) { throw error; } } }
public void Oneway(Command command) { Exception error = null; try { reconnectMutex.WaitOne(); if (IsShutdownCommand(command) && ConnectedTransport == null) { if (command.IsShutdownInfo) { // Skipping send of ShutdownInfo command when not connected. return; } if (command is RemoveInfo) { // Simulate response to RemoveInfo command Response response = new Response(); response.CorrelationId = command.CommandId; onCommand(this, response); return; } } // Keep trying until the message is sent. for (int i = 0; !disposed; i++) { try { // Wait for transport to be connected. ITransport transport = ConnectedTransport; while (transport == null && !disposed && connectionFailure == null // && !Thread.CurrentThread.isInterrupted() ) { Tracer.Info("Waiting for transport to reconnect."); try { // Release so that the reconnect task can run reconnectMutex.ReleaseMutex(); try { // Wait for something Thread.Sleep(1000); } catch (ThreadInterruptedException e) { Tracer.DebugFormat("Interrupted: {0}", e.Message); } } finally { reconnectMutex.WaitOne(); } transport = ConnectedTransport; } if (transport == null) { // Previous loop may have exited due to use being disposed. if (disposed) { error = new IOException("Transport disposed."); } else if (connectionFailure != null) { error = connectionFailure; } else { error = new IOException("Unexpected failure."); } break; } // If it was a request and it was not being tracked by // the state tracker, then hold it in the requestMap so // that we can replay it later. Tracked tracked = stateTracker.track(command); lock (((ICollection)requestMap).SyncRoot) { if (tracked != null && tracked.WaitingForResponse) { requestMap.Add(command.CommandId, tracked); } else if (tracked == null && command.ResponseRequired) { requestMap.Add(command.CommandId, command); } } // Send the message. try { transport.Oneway(command); stateTracker.trackBack(command); } catch (Exception e) { // If the command was not tracked.. we will retry in // this method if (tracked == null) { // since we will retry in this method.. take it // out of the request map so that it is not // sent 2 times on recovery if (command.ResponseRequired) { lock (((ICollection)requestMap).SyncRoot) { requestMap.Remove(command.CommandId); } } // Rethrow the exception so it will handled by // the outer catch throw e; } } return; } catch (Exception e) { Tracer.DebugFormat("Send Oneway attempt: {0} failed.", i); handleTransportFailure(e); } } } finally { reconnectMutex.ReleaseMutex(); } if (!disposed) { if (error != null) { throw error; } } }