private void TryHandleMessage(object message) { var messageID = MessageId(message).ToString(); logger.Debug("Received message {0} from queue {1}", messageID, QueueName); // NOTE this method _should not_ throw an exception! try { var transportMessage = new IncomingTransportMessage(messageID, new Dictionary <string, string>(), message); Exception lastException = null; if (faultManager.HasMaxRetriesExceeded(transportMessage, out lastException)) { logger.Debug("MaxRetriesExceeded. Will not re-enque.", messageID.ToString(), QueueName); OnPoisonMessageDetected(new PoisonMessageDetectedEventArgs() { QueueName = QueueName, Retries = MaxRetries, Exception = lastException, MessageId = messageID, ErrorCode = "MaxRetriesExceeded", }); return; // return without error to commit transaction } logger.Debug("Notifying observers of new TransportMessage for message {0} from queue {1}.", messageID.ToString(), QueueName); OnMessageAvailable(transportMessage); faultManager.ClearFailuresForMessage(messageID); logger.Debug("Committed message {0} from queue {1}", messageID.ToString(), QueueName); } catch (Exception e) { faultManager.IncrementFailuresForMessage(messageID.ToString(), e); logger.Error(e, "Exception caught handling message {0} from queue {1}. Re-enqueing.", messageID, QueueName); Thread.Sleep(1000); // TODO possibly implement a backoff with the fault manager based on number of retries? queue.Enqueue(message); queueNotifier.Set(); } }
private void TryHandleMessage(SqlTransaction transaction, ServiceBrokerMessage message) { logger.Debug("Received message {0} from queue {1}", message.ConversationHandle, ServiceBrokerQueue); // NOTE this method _should not_ throw an exception! // It is responsible for committing or rolling back the SqlTransaction // that was passed in. // We can keep track of the openTransaction on the current thread in case we need it. SqlServerTransactionManager.SaveTransactionForCurrentTask(transaction); try { // this may throw an exception if we need to rollback TryHandleMessageInner(transaction, message); // End the conversation and commit ServiceBrokerWrapper.EndConversation(transaction, message.ConversationHandle); SqlServerTransactionManager.CommitTransactionAndDisposeConnection(transaction); faultManager.ClearFailuresForMessage(message.ConversationHandle.ToString()); logger.Debug("Committed message {0} from queue {1}", message.ConversationHandle, ServiceBrokerQueue); } catch (Exception e) { SqlServerTransactionManager.TryRollbackTransaction(transaction); faultManager.IncrementFailuresForMessage(message.ConversationHandle.ToString(), e); logger.Error(e, "Exception caught handling message {0} from queue {1}. Rolling back transaction to retry.", message.ConversationHandle, ServiceBrokerQueue); #if DEBUG if (System.Diagnostics.Debugger.IsAttached) { // System.Diagnostics.Debugger.Break(); } #endif } finally { SqlServerTransactionManager.ClearTransactionForCurrentTask(); SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction); // shoud not throw exception } }
private void TryHandleMessage(ReceiverLink receiverLink, Message amqpMessage) { // NOTE this method _should not_ throw an exception! var threadName = receiverLink.Name; var messageID = amqpMessage.Properties?.MessageId ?? "?"; try { logger.Debug("{0}: Received Message with MessageId={1}", threadName, messageID); var headers = new Dictionary <string, string>(); if (amqpMessage.ApplicationProperties != null) { foreach (var key in amqpMessage.ApplicationProperties.Map.Keys) { headers[key.ToString()] = amqpMessage.ApplicationProperties.Map[key].ToString(); } } object message = null; try { message = DecodeMessage(amqpMessage); } catch (Exception e) { logger.Error(e, "{0}: Cannot Decode Message. Will not re-enqueue.", threadName); OnPoisonMessageDetected(new PoisonMessageDetectedEventArgs() { QueueName = ReceiverLinkAddress, Retries = MaxRetries, Exception = e, MessageId = messageID, ErrorCode = "DecodeException", }); } if (message != null) { var transportMessage = new IncomingTransportMessage(messageID, headers, message); Exception lastException = null; if (faultManager.HasMaxRetriesExceeded(transportMessage, out lastException)) { logger.Error(lastException, "{0}: MaxRetriesExceeded for MessageId={1}. Will not re-enqueue.", threadName, messageID.ToString()); OnPoisonMessageDetected(new PoisonMessageDetectedEventArgs() { QueueName = ReceiverLinkAddress, Retries = MaxRetries, Exception = lastException, MessageId = messageID, ErrorCode = "MaxRetriesExceeded", }); } else { logger.Debug("{0}: Notifying observers of new TransportMessage for MessageId={1}.", threadName, messageID.ToString()); OnMessageAvailable(transportMessage); faultManager.ClearFailuresForMessage(messageID); } } receiverLink.Accept(amqpMessage); logger.Debug("{0}: Accepting MessageId={1}", threadName, messageID.ToString()); } catch (Exception e) { faultManager.IncrementFailuresForMessage(messageID.ToString(), e); receiverLink.Reject(amqpMessage); logger.Error(e, "{0}: Exception caught handling MessageId={1}. Rejecting.", threadName, messageID.ToString()); Thread.Sleep(1000); // TODO possibly implement a backoff with the fault manager based on number of retries? } }