Example #1
0
        /// <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);
        }
Example #2
0
        /// <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)
        {
            try
            {
                queuedMessage = queuedMessage.NextAttempt();
                var acknowledged = await HandleMessageReceived(queuedMessage, cancellationToken);

                if (acknowledged)
                {
                    await HandleMessageAcknowledged(queuedMessage, cancellationToken);

                    return;
                }

                await DiagnosticService.EmitAsync(
                    new DiagnosticEventBuilder(this, DiagnosticEventType.MessageNotAcknowledged)
                {
                    Message = queuedMessage.Message,
                    Queue   = QueueName
                }.Build(), cancellationToken);

                if (queuedMessage.Attempts >= _maxAttempts)
                {
                    await HandleMaximumAttemptsExceeded(queuedMessage, cancellationToken);

                    return;
                }

                await HandleAcknowledgementFailure(queuedMessage);

                DiagnosticService.Emit(
                    new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageRetry)
                {
                    Detail  = "Message not acknowledged; retrying in " + _retryDelay,
                    Message = queuedMessage.Message,
                    Queue   = QueueName
                }.Build());

                ScheduleRetry(queuedMessage, cancellationToken);
            }
            catch (Exception ex)
            {
                // Catch all.  Do not let any exceptions propagate outside of this method!
                DiagnosticService.Emit(
                    new DiagnosticEventBuilder(this, DiagnosticEventType.QueuedMessageProcessingError)
                {
                    Detail    = "Unhandled exception processing queued message",
                    Message   = queuedMessage.Message,
                    Queue     = QueueName,
                    Exception = ex
                }.Build());
            }
        }
Example #3
0
        private async Task <bool> HandleMessageReceived(QueuedMessage queuedMessage, CancellationToken cancellationToken)
        {
            Message    message                 = null;
            var        acknowledged            = false;
            IPrincipal originalThreadPrincipal = null;

            try
            {
                originalThreadPrincipal = Thread.CurrentPrincipal;
                message       = queuedMessage.Message;
                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, queuedMessage.Principal);

                Thread.CurrentPrincipal = context.Principal;
                cancellationToken.ThrowIfCancellationRequested();

                await _listener.MessageReceived(message, context, cancellationToken);

                if (_autoAcknowledge && !context.Acknowledged)
                {
                    await context.Acknowledge();
                }

                acknowledged = context.Acknowledged;
            }
            catch (Exception ex)
            {
                DiagnosticService.Emit(new DiagnosticEventBuilder(this, DiagnosticEventType.UnhandledException)
                {
                    Detail    = "Unhandled exception handling queued message",
                    Message   = message,
                    Queue     = QueueName,
                    Exception = ex
                }.Build());
            }
            finally
            {
                Thread.CurrentPrincipal = originalThreadPrincipal;
            }

            return(acknowledged);
        }
        private void ScheduleRetry(QueuedMessage queuedMessage, CancellationToken cancellationToken)
        {
            Task.Factory.StartNew(() =>
            {
                Task.Delay(_retryDelay, cancellationToken).Wait(cancellationToken);
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                _queuedMessages.Post(queuedMessage);

                DiagnosticService.EmitAsync(
                    new DiagnosticEventBuilder(this, DiagnosticEventType.MessageRequeued)
                {
                    Detail  = "Message requeued (retry)",
                    Message = queuedMessage.Message,
                    Queue   = QueueName
                }.Build(), cancellationToken);
            },
                                  TaskCreationOptions.LongRunning);
        }
Example #5
0
 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);
        }
Example #7
0
 /// <summary>
 /// Initializes a new <see cref="MessageQueueEventArgs"/>
 /// </summary>
 /// <param name="queue">The name of the queue from which the message was read</param>
 /// <param name="queuedMessage">The queued message for which the handling attempt was made</param>
 /// <param name="exception">The exception that was caught</param>
 public MessageQueueEventArgs(QueueName queue, QueuedMessage queuedMessage, Exception exception)
 {
     Queue         = queue;
     QueuedMessage = queuedMessage;
     Exception     = exception;
 }
Example #8
0
 /// <summary>
 /// Initializes a new <see cref="MessageQueueEventArgs"/>
 /// </summary>
 /// <param name="queue">The name of the queue from which the message was read</param>
 /// <param name="queuedMessage">The queued message for which the handling attempt was made</param>
 public MessageQueueEventArgs(QueueName queue, QueuedMessage queuedMessage)
 {
     Queue         = queue;
     QueuedMessage = queuedMessage;
 }