private void TryReceiveMessage() { // NOTE this method _should not_ throw an exception! ServiceBrokerMessage message = null; SqlTransaction transaction = null; try { transaction = SqlServerTransactionManager.BeginTransaction(ConnectionString); logger.Debug("RECEIVE FROM {0}", ServiceBrokerQueue); message = ServiceBrokerWrapper.WaitAndReceive(transaction, ServiceBrokerQueue, waitTimeout); } catch (Exception e) { logger.Error(e, "Exception caught trying to receive from queue {0}. Rolling back and backing off before reconnecting.", ServiceBrokerQueue); SqlServerTransactionManager.TryRollbackTransaction(transaction); SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction); Thread.Sleep(1000); // back-off because we will return and loop immediately workerThreadPool.Release(1); // always release before returning! return; } // No message? That's okay if (message == null) { try { SqlServerTransactionManager.CommitTransactionAndDisposeConnection(transaction); } catch (Exception) { SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction); throw; } workerThreadPool.Release(1); // always release before returning! return; } // start a Task.Run(() => { // TryHandleHessage _should not_ throw an exception. It will also commit and cleanup the transactions try { TryHandleMessage(transaction, message); } finally { var previousCount = workerThreadPool.Release(1); // release this semaphore back to the pool regardless of what happened logger.Debug("Current Concurrent Requests = {0}", MaxConcurrency - previousCount); } }); }
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 } }