bool HandleClientOperationFailure(Exception exception) { SendOperation sendOperation = this.messageRpc.Operations[0]; if (TD.RoutingServiceTransmitFailedIsEnabled()) { TD.RoutingServiceTransmitFailed(this.messageRpc.EventTraceActivity, sendOperation.CurrentEndpoint.ToString(), exception); } if (!(exception is CommunicationException || exception is TimeoutException)) { //We only move to backup for CommunicationExceptions and TimeoutExceptions return(false); } if ((exception is CommunicationObjectAbortedException || exception is CommunicationObjectFaultedException) && !this.service.ChannelExtension.HasSession) { // Messages on a non sessionful channel share outbound connections and can // fail due to other messages failing on the same channel if (messageRpc.Transaction == null && !this.abortedRetry) { //No session and non transactional, retry the message 1 time (before moving to backup) this.abortedRetry = true; return(true); } } else if (exception is EndpointNotFoundException) { // The channel may not fault for this exception for bindings other than netTcpBinding // We abort the channel in that case. We proactively clean up so that we don't have to cleanup later SessionChannels sessionChannels = this.service.GetSessionChannels(this.messageRpc.Impersonating); if (sessionChannels != null) { sessionChannels.AbortChannel(sendOperation.CurrentEndpoint); } } else if (exception is MessageSecurityException) { // The service may have been stopped and restarted without the routing service knowledge. // When we try to use a cached channel to the service, the channel can fault due to this exception // The faulted channel gets cleaned up and we retry one more time only when service has backup // If there is no backup, we do not retry since we do not create a buffered message to prevent performance degradation if (!this.abortedRetry && (sendOperation.AlternateEndpointCount > 0)) { this.abortedRetry = true; return(true); } } else if (exception is ProtocolException) { // This exception may happen when the current cached channel was closed due to end service recycles. // We abort the channel in this case and clean it up from the session. // We will then retry the request one more time only. In retried request, it will create a new channel because the cached channel has been cleaned up. if (!this.abortedRetry) { SessionChannels sessionChannels = this.service.GetSessionChannels(this.messageRpc.Impersonating); if (sessionChannels != null) { this.abortedRetry = true; sessionChannels.AbortChannel(sendOperation.CurrentEndpoint); return(true); } } } if (sendOperation.TryMoveToAlternate(exception)) { if (TD.RoutingServiceMovedToBackupIsEnabled()) { TD.RoutingServiceMovedToBackup(this.messageRpc.EventTraceActivity, messageRpc.UniqueID, "0", sendOperation.CurrentEndpoint.ToString()); } return(true); } return(false); }
bool HandleClientOperationFailure(Exception e) { if (TD.RoutingServiceTransmitFailedIsEnabled()) { TD.RoutingServiceTransmitFailed(null, this.client.Key.ToString(), e); } if (!(e is CommunicationException || e is TimeoutException)) { //We only move to backup for CommunicationExceptions and TimeoutExceptions return(false); } bool canHandle; MessageRpc messageRpc = this.service.SessionMessages[this.sessionMessageIndex]; SendOperation sendOperation = messageRpc.Operations[this.destinationIndex]; if ((e is CommunicationObjectAbortedException || e is CommunicationObjectFaultedException) && !this.channelExtension.HasSession) { // Messages on a non sessionful channel share outbound connections and can // fail due to other messages failing on the same channel bool canRetry = (this.channelExtension.ReceiveContextEnabled || !this.channelExtension.TransactedReceiveEnabled); if (canRetry && !this.abortedRetry) { //No session and ReceiveContext or non transactional, retry the message 1 time (before moving to backup) this.abortedRetry = true; this.ResetState(); return(true); } } else if (e is EndpointNotFoundException) { // The channel may not fault for this exception for bindings other than netTcpBinding // We abort the channel in that case. We proactively clean up so that we don't have to cleanup later SessionChannels sessionChannels = this.service.GetSessionChannels(messageRpc.Impersonating); if (sessionChannels != null) { sessionChannels.AbortChannel(sendOperation.CurrentEndpoint); } } else if (e is MessageSecurityException) { // The service may have been stopped and restarted without the routing service knowledge. // When we try to use a cached channel to the service, the channel can fault due to this exception // The faulted channel gets cleaned up and we retry one more time only when service has backup // If there is no backup, we do not retry since we do not create a buffered message to prevent performance degradation if (!this.abortedRetry && (sendOperation.AlternateEndpointCount > 0)) { this.abortedRetry = true; this.ResetState(); return(true); } } if (sendOperation.TryMoveToAlternate(e)) { if (TD.RoutingServiceMovedToBackupIsEnabled()) { TD.RoutingServiceMovedToBackup(messageRpc.EventTraceActivity, messageRpc.UniqueID, this.destinationIndex.ToString(TD.Culture), sendOperation.CurrentEndpoint.ToString()); } this.ResetState(); canHandle = true; } else if (this.service.GetTransactionForSending(messageRpc) == null) { // This is OneWay with no Transaction... // store this exception for when we complete, but continue any multicasting this.service.SessionException = e; // Mark the SendOperation as 'Sent' because there's no more work we can do (non-tx and no more backups) sendOperation.TransmitSucceeded(null); if (this.channelExtension.HasSession) { this.channelExtension.SessionChannels.AbortChannel(this.client.Key); } this.MoveToNextClientOperation(messageRpc.Operations.Count); canHandle = true; } else { canHandle = false; } return(canHandle); }