Пример #1
0
        private async Task BulkDispatchAsync(IEnumerable <Message> posts, CancellationToken cancellationToken)
        {
            //Chunk into Topics
            var messagesByTopic = posts.GroupBy(m => m.Header.Topic);

            foreach (var topicBatch in messagesByTopic)
            {
                var producer = ProducerRegistry.LookupByOrDefault(topicBatch.Key);

                if (producer is IAmABulkMessageProducerAsync bulkMessageProducer)
                {
                    var messages = topicBatch.ToArray();
                    s_logger.LogInformation("Bulk Dispatching {NumberOfMessages} for Topic {TopicName}", messages.Length, topicBatch.Key);
                    var dispatchesMessages = bulkMessageProducer.SendAsync(messages, cancellationToken);

                    await foreach (var successfulMessage in dispatchesMessages.WithCancellation(cancellationToken))
                    {
                        if (!(producer is ISupportPublishConfirmation))
                        {
                            await RetryAsync(async ct => await AsyncOutbox.MarkDispatchedAsync(successfulMessage,
                                                                                               DateTime.UtcNow, cancellationToken: cancellationToken), cancellationToken : cancellationToken);
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException("No async bulk message producer defined.");
                }
            }
        }
Пример #2
0
        internal async Task ClearOutboxAsync(IEnumerable <Guid> posts, bool continueOnCapturedContext = false,
                                             CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!HasAsyncOutbox())
            {
                throw new InvalidOperationException("No async outbox defined.");
            }

            await _clearSemaphoreToken.WaitAsync(cancellationToken);

            try
            {
                foreach (var messageId in posts)
                {
                    var message = await AsyncOutbox.GetAsync(messageId, OutboxTimeout, cancellationToken);

                    if (message == null || message.Header.MessageType == MessageType.MT_NONE)
                    {
                        throw new NullReferenceException($"Message with Id {messageId} not found in the Outbox");
                    }

                    await DispatchAsync(new[] { message }, continueOnCapturedContext, cancellationToken);
                }
            }
            finally
            {
                _clearSemaphoreToken.Release();
            }

            CheckOutstandingMessages();
        }
Пример #3
0
        internal async Task AddToOutboxAsync <T>(T request, bool continueOnCapturedContext, CancellationToken cancellationToken, Message message, IAmABoxTransactionConnectionProvider overridingTransactionConnectionProvider = null)
            where T : class, IRequest
        {
            CheckOutboxOutstandingLimit();

            var written = await RetryAsync(async ct => { await AsyncOutbox.AddAsync(message, OutboxTimeout, ct, overridingTransactionConnectionProvider).ConfigureAwait(continueOnCapturedContext); },
                                           continueOnCapturedContext, cancellationToken).ConfigureAwait(continueOnCapturedContext);

            if (!written)
            {
                throw new ChannelFailureException($"Could not write request {request.Id} to the outbox");
            }
        }
Пример #4
0
        private async Task DispatchAsync(IEnumerable <Message> posts, bool continueOnCapturedContext, CancellationToken cancellationToken)
        {
            foreach (var message in posts)
            {
                s_logger.LogInformation("Decoupled invocation of message: Topic:{Topic} Id:{Id}", message.Header.Topic, message.Id.ToString());

                var producer = ProducerRegistry.LookupByOrDefault(message.Header.Topic);

                if (producer is IAmAMessageProducerAsync producerAsync)
                {
                    if (producer is ISupportPublishConfirmation)
                    {
                        //mark dispatch handled by a callback - set in constructor
                        await RetryAsync(
                            async ct =>
                            await producerAsync.SendAsync(message).ConfigureAwait(continueOnCapturedContext),
                            continueOnCapturedContext,
                            cancellationToken)
                        .ConfigureAwait(continueOnCapturedContext);
                    }
                    else
                    {
                        var sent = await RetryAsync(
                            async ct =>
                            await producerAsync.SendAsync(message).ConfigureAwait(continueOnCapturedContext),
                            continueOnCapturedContext,
                            cancellationToken)
                                   .ConfigureAwait(continueOnCapturedContext);

                        if (sent)
                        {
                            await RetryAsync(async ct => await AsyncOutbox.MarkDispatchedAsync(message.Id, DateTime.UtcNow, cancellationToken: cancellationToken),
                                             cancellationToken : cancellationToken);
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException("No async message producer defined.");
                }
            }
        }
Пример #5
0
        private async Task BackgroundDispatchUsingAsync(int amountToClear, int minimumAge, bool useBulk)
        {
            if (await _backgroundClearSemaphoreToken.WaitAsync(TimeSpan.Zero))
            {
                await _clearSemaphoreToken.WaitAsync(CancellationToken.None);

                try
                {
                    var messages =
                        await AsyncOutbox.OutstandingMessagesAsync(minimumAge, amountToClear);

                    s_logger.LogInformation("Found {NumberOfMessages} to clear out of amount {AmountToClear}",
                                            messages.Count(), amountToClear);

                    if (useBulk)
                    {
                        await BulkDispatchAsync(messages, CancellationToken.None);
                    }
                    else
                    {
                        await DispatchAsync(messages, false, CancellationToken.None);
                    }

                    s_logger.LogInformation("Messages have been cleared");
                }
                catch (Exception e)
                {
                    s_logger.LogError(e, "Error while dispatching from outbox");
                }
                finally
                {
                    _clearSemaphoreToken.Release();
                    _backgroundClearSemaphoreToken.Release();
                }

                CheckOutstandingMessages();
            }
            else
            {
                s_logger.LogInformation("Skipping dispatch of messages as another thread is running");
            }
        }
Пример #6
0
        internal bool ConfigureAsyncPublisherCallbackMaybe(IAmAMessageProducer producer)
        {
            if (producer is ISupportPublishConfirmation producerSync)
            {
                producerSync.OnMessagePublished += async delegate(bool success, Guid id)
                {
                    if (success)
                    {
                        s_logger.LogInformation("Sent message: Id:{Id}", id.ToString());
                        if (AsyncOutbox != null)
                        {
                            await RetryAsync(async ct => await AsyncOutbox.MarkDispatchedAsync(id, DateTime.UtcNow));
                        }
                    }
                };
                return(true);
            }

            return(false);
        }