/// <summary> /// Posts the specified request with async/await support. The message is placed on a task queue and into a message store for reposting in the event of failure. /// You will need to configure a service that reads from the task queue to process the message /// Paramore.Brighter.ServiceActivator provides an endpoint for use in a windows service that reads from a queue /// and then Sends or Publishes the message to a <see cref="CommandProcessor"/> within that service. The decision to <see cref="Send{T}"/> or <see cref="Publish{T}"/> is based on the /// mapper. Your mapper can map to a <see cref="Message"/> with either a <see cref="T:MessageType.MT_COMMAND"/> , which results in a <see cref="Send{T}(T)"/> or a /// <see cref="T:MessageType.MT_EVENT"/> which results in a <see cref="Publish{T}(T)"/> /// </summary> /// <typeparam name="T"></typeparam> /// <param name="request">The request.</param> /// <param name="continueOnCapturedContext">Should we use the calling thread's synchronization context when continuing or a default thread synchronization context. Defaults to false</param> /// <param name="cancellationToken">Allows the sender to cancel the request pipeline. Optional</param> /// <exception cref="System.ArgumentOutOfRangeException"></exception> /// <returns>awaitable <see cref="Task"/>.</returns> public async Task PostAsync <T>(T request, bool continueOnCapturedContext = false, CancellationToken cancellationToken = default(CancellationToken)) where T : class, IRequest { _logger.Value.InfoFormat("Async decoupled invocation of request: {0} {1}", request.GetType(), request.Id); if (_asyncMessageStore == null) { throw new InvalidOperationException("No async message store defined."); } if (_asyncMessageProducer == null) { throw new InvalidOperationException("No async message producer defined."); } var messageMapper = _mapperRegistry.Get <T>(); if (messageMapper == null) { throw new ArgumentOutOfRangeException($"No message mapper registered for messages of type: {typeof(T)}"); } var message = messageMapper.MapToMessage(request); await RetryAndBreakCircuitAsync(async ct => { await _asyncMessageStore.AddAsync(message, _messageStoreTimeout, ct).ConfigureAwait(continueOnCapturedContext); await _asyncMessageProducer.SendAsync(message).ConfigureAwait(continueOnCapturedContext); }, continueOnCapturedContext, cancellationToken).ConfigureAwait(continueOnCapturedContext); }
/// <summary> /// Flushes the message box message given by <param name="posts"> to the broker. /// Intended for use with the Outbox pattern: http://gistlabs.com/2014/05/the-outbox/ <see cref="DepositPostBoxAsync"/> /// </summary> /// <param name="posts">The posts to flush</param> public async Task ClearOutboxAsync(IEnumerable <Guid> posts, bool continueOnCapturedContext = false, CancellationToken cancellationToken = default(CancellationToken)) { if (_asyncOutbox == null) { throw new InvalidOperationException("No async outbox defined."); } if (_asyncMessageProducer == null) { throw new InvalidOperationException("No async message producer defined."); } foreach (var messageId in posts) { var message = await _asyncOutbox.GetAsync(messageId, _outboxTimeout, cancellationToken); if (message == null) { throw new NullReferenceException($"Message with Id {messageId} not found in the Outbox"); } _logger.Value.InfoFormat("Decoupled invocation of message: Topic:{0} Id:{1}", message.Header.Topic, messageId.ToString()); await RetryAndBreakCircuitAsync( async ct => await _asyncMessageProducer.SendAsync(message).ConfigureAwait(continueOnCapturedContext), continueOnCapturedContext, cancellationToken).ConfigureAwait(continueOnCapturedContext); } }