Ejemplo n.º 1
0
        async Task <SqlConnection> GetOpenConnectionAsync(TriggerListenerOptions options)
        {
            var connection = new SqlConnection(options.ConnectionString);

            if (connection.State == ConnectionState.Closed)
            {
                await connection.OpenAsync().ConfigureAwait(false);
            }

            return(connection);
        }
Ejemplo n.º 2
0
        void InitializeSqlStatements(TriggerListenerOptions options)
        {
            var commandBuilder     = new SqlCommandBuilder();
            var sanitizedQueueName = commandBuilder.QuoteIdentifier(options.QueueName);

            _receiveSql = $@"WAITFOR (
                                 RECEIVE TOP({options.MaximumBatchSize})
                                     message_type_name,
                                     CAST(message_body AS XML) AS message_body,
                                     conversation_handle
                                 FROM messaging.{sanitizedQueueName}
                             ), TIMEOUT {options.ReceiveTimeout.TotalMilliseconds};";
        }
Ejemplo n.º 3
0
        public void Start(TriggerListenerOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (_running)
            {
                throw new InvalidOperationException("The message listener is already running.");
            }

            Log.Info($"Beginning listening on queue {options.QueueName}.");

            _running = true;
            InitializeSqlStatements(options);

            _listenTask = Task.Run(async() => await Listen(options, cancellationToken).ConfigureAwait(false), cancellationToken);
        }
Ejemplo n.º 4
0
        protected async Task Listen(TriggerListenerOptions options, CancellationToken cancellationToken)
        {
            var currentIteration = 0L;

            while (!_done)
            {
                try
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                    }

                    currentIteration++;

                    Log.Debug($"Iteration {currentIteration}: Beginning.");

                    // Connect to the database
                    using (var connection = await GetOpenConnectionAsync(options).ConfigureAwait(false))
                        using (var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted))
                        {
                            Log.Debug($"Iteration {currentIteration}: Connection opened.");

                            // Read messages from the Service Broker queue
                            var messages = await ReceiveMessagesAsync(transaction, currentIteration).ConfigureAwait(false) ?? new List <TriggerMessage>();

                            try
                            {
                                // If the last message is an EndOfStream message, we need to end the conversation after
                                // processing all other messages.
                                var endOfStreamMessage = (messages.LastOrDefault()?.MessageType == END_OF_STREAM) ? messages.Last() : null;

                                if (endOfStreamMessage != null)
                                {
                                    messages.RemoveAt(messages.Count - 1);
                                }

                                // Process the messages.
                                if (messages.Any())
                                {
                                    Log.Debug($"Iteration {currentIteration}: Preparing to process {messages.Count} message(s).");

                                    await ProcessMessagesAsync(messages).ConfigureAwait(false);

                                    Log.Debug($"Iteration {currentIteration}: Successfully processed {messages.Count} message(s).");
                                }

                                // If all messages were processed successfully, commit the transaction to
                                // remove the messages from the queue.
                                await CommitAsync(transaction, currentIteration).ConfigureAwait(false);

                                if (endOfStreamMessage != null)
                                {
                                    await EndConversationAsync(endOfStreamMessage.ConversationHandle, connection, currentIteration).ConfigureAwait(false);
                                }
                            }
                            catch (Exception ex)
                            {
                                Log.Error(
                                    $"An error occurred while processing a message from queue {options.QueueName}. Potential data inconsistency if messages were processed. Rolling back RECEIVE action.",
                                    ex);

                                // If there was an error processing any of the messages, roll back the transaction
                                // to return the messages to the queue.
                                await RollbackAsync(transaction, currentIteration).ConfigureAwait(false);
                            }
                        }
                }
                catch (Exception ex)
                {
                    Log.Error("An error occurred while processing messages.", ex);

                    await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
                }
            }
        }