async Task <SqlConnection> GetOpenConnectionAsync(TriggerListenerOptions options) { var connection = new SqlConnection(options.ConnectionString); if (connection.State == ConnectionState.Closed) { await connection.OpenAsync().ConfigureAwait(false); } return(connection); }
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};"; }
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); }
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); } } }