/// <summary> /// Adds a message to the queue /// </summary> /// <param name="message">The message to add</param> /// <param name="principal">The principal that sent the message or from whom /// the message was received</param> /// <param name="cancellationToken">A cancellation token that can be used by the caller /// to cancel the enqueueing operation</param> /// <returns>Returns a task that completes when the message has been added to the queue</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="message"/> is /// <c>null</c></exception> /// <exception cref="ObjectDisposedException">Thrown if this SQL message queue instance /// has already been disposed</exception> public virtual async Task Enqueue(Message message, IPrincipal principal, CancellationToken cancellationToken = default(CancellationToken)) { if (message == null) { throw new ArgumentNullException(nameof(message)); } CheckDisposed(); var queuedMessage = new QueuedMessage(message, principal, 0); var handler = MessageEnqueued; if (handler != null) { var args = new MessageQueueEventArgs(QueueName, queuedMessage); await MessageEnqueued(this, args); } await _queuedMessages.SendAsync(queuedMessage, cancellationToken); // TODO: handle accepted == false await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageEnqueued) { Detail = "New message enqueued", Message = message, Queue = QueueName }.Build(), cancellationToken); }
private async Task HandleMaximumAttemptsExceeded(QueuedMessage queuedMessage, CancellationToken cancellationToken) { try { var eventArgs = new MessageQueueEventArgs(QueueName, queuedMessage, null); await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MaxAttemptsExceeded) { Detail = "Maximum attempts exceeded (" + _maxAttempts + ")", Message = queuedMessage.Message, Queue = QueueName }.Build(), cancellationToken); var maxAttemptsExceededHandlers = MaximumAttemptsExceeded; if (maxAttemptsExceededHandlers != null) { await MaximumAttemptsExceeded(this, eventArgs); } } catch (Exception ex) { DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.MaxAttemptsExceededError) { Detail = "Unexpected error handling maximum attempts exceeded", Message = queuedMessage.Message, Queue = QueueName, Exception = ex }.Build()); } }
private async Task HandleMessageAcknowledged(QueuedMessage queuedMessage, CancellationToken cancellationToken) { try { var eventArgs = new MessageQueueEventArgs(QueueName, queuedMessage); await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageAcknowledged) { Message = queuedMessage.Message, Queue = QueueName }.Build(), cancellationToken); var messageAcknowledgedHandlers = MessageAcknowledged; if (messageAcknowledgedHandlers != null) { await messageAcknowledgedHandlers(this, eventArgs); } } catch (Exception ex) { DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.MessageAcknowledgementError) { Detail = "Unexpected error handling message acknowledgement", Message = queuedMessage.Message, Queue = QueueName, Exception = ex }.Build()); } }
private async Task HandleAcknowledgementFailure(QueuedMessage queuedMessage) { try { var acknowledgementFailureHandlers = AcknowledgementFailure; if (acknowledgementFailureHandlers != null) { var eventArgs = new MessageQueueEventArgs(QueueName, queuedMessage, null); await AcknowledgementFailure(this, eventArgs); } } catch (Exception ex) { DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.MessageAcknowledgementError) { Detail = "Unexpected error handling message acknowledgement failure", Message = queuedMessage.Message, Queue = QueueName, Exception = ex }.Build()); } }
/// <summary> /// Called by the message processing loop to process an individual message /// </summary> /// <param name="queuedMessage">The queued message to process</param> /// <param name="cancellationToken">A cancellation token that can be used by the caller /// to cancel message processing operation</param> /// <returns>Returns a task that completes when the queued message is processed</returns> protected virtual async Task ProcessQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken) { Exception exception = null; var message = queuedMessage.Message; var principal = queuedMessage.Principal; // ReSharper disable once ConditionIsAlwaysTrueOrFalse queuedMessage = queuedMessage.NextAttempt(); await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageAttempt) { Detail = "Processing queued message (attempt " + queuedMessage.Attempts + " of " + _maxAttempts + ")", Message = message, Queue = QueueName }.Build(), cancellationToken); var context = new QueuedMessageContext(message, principal); Thread.CurrentPrincipal = context.Principal; cancellationToken.ThrowIfCancellationRequested(); try { await _listener.MessageReceived(message, context, cancellationToken); if (_autoAcknowledge && !context.Acknowledged) { await context.Acknowledge(); } } catch (Exception ex) { exception = ex; DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.UnhandledException) { Detail = "Unhandled exception handling queued message", Message = message, Queue = QueueName, Exception = ex }.Build()); } var eventArgs = new MessageQueueEventArgs(QueueName, queuedMessage, exception); if (context.Acknowledged) { await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageAcknowledged) { Message = message, Queue = QueueName }.Build(), cancellationToken); var messageAcknowledgedHandlers = MessageAcknowledged; if (messageAcknowledgedHandlers != null) { await messageAcknowledgedHandlers(this, eventArgs); } return; } await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MessageNotAcknowledged) { Message = message, Queue = QueueName }.Build(), cancellationToken); if (queuedMessage.Attempts >= _maxAttempts) { await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.MaxAttemptsExceeded) { Detail = "Maximum attempts exceeded (" + _maxAttempts + ")", Message = message, Queue = QueueName }.Build(), cancellationToken); var maxAttemptsExceededHandlers = MaximumAttemptsExceeded; if (maxAttemptsExceededHandlers != null) { await MaximumAttemptsExceeded(this, eventArgs); } return; } var acknowledgementFailureHandlers = AcknowledgementFailure; if (acknowledgementFailureHandlers != null) { await AcknowledgementFailure(this, eventArgs); } await DiagnosticService.EmitAsync( new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageRetry) { Detail = "Message not acknowledged; retrying in " + _retryDelay, Message = message, Queue = QueueName }.Build(), cancellationToken); ScheduleRetry(queuedMessage, cancellationToken); }