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
            }
        }