public async Task Dispatch <TMessage>(TMessage message, IMessageHandlerContext messageHandlerContext) where TMessage : IMessage { try { await _messageDispatcher.Dispatch(message, messageHandlerContext).ConfigureAwait(false); if (messageHandlerContext is IMessageBrokerContext messageBrokerContext) { messageBrokerContext.Container.TryGet <ReplyToRoutingContext>(out var replyContext); await _replyRouter.Route(messageBrokerContext.BrokeredMessage, messageBrokerContext.GetTransactionContext(), replyContext).ConfigureAwait(false); messageBrokerContext.Container.TryGet <RoutingContext>(out var forwardContext); await _forwardMessages.Route(messageBrokerContext.BrokeredMessage, forwardContext?.DestinationPath, messageBrokerContext.GetTransactionContext()).ConfigureAwait(false); } } catch (Exception dispatchFailureException) { if (messageHandlerContext is IMessageBrokerContext messageBrokerContext) { if (!(messageBrokerContext.Container.TryGet <CompensationRoutingContext>(out var compensateContext))) { throw; } var details = $"{dispatchFailureException.Message} -> {dispatchFailureException.StackTrace}"; var description = $"'{typeof(TMessage).Name}' was not received successfully"; var newContext = new CompensationRoutingContext(compensateContext?.DestinationPath, details, description, messageBrokerContext?.Container); messageBrokerContext?.Container.Include(newContext); messageBrokerContext.Container.TryGet <CompensationRoutingContext>(out var compensationRoutingContext); await _compensatingRouter.Route(messageBrokerContext.BrokeredMessage, messageBrokerContext.GetTransactionContext(), compensationRoutingContext).ConfigureAwait(false); } else { throw; } } }
///<inheritdoc/> public Task Route(InboundBrokeredMessage inboundBrokeredMessage, TransactionContext transactionContext, CompensationRoutingContext compensateContext) { if (!(compensateContext.Container.TryGet <Message>(out var receivedMessage))) { throw new InvalidOperationException($"The received {nameof(CompensationRoutingContext)} did not contain a {typeof(Message).Name}"); } if (!(transactionContext.Container.TryGet <MessageReceiver>(out var receiver))) { throw new InvalidOperationException($"The received {nameof(TransactionContext)} did not contain a {typeof(MessageReceiver).Name}"); } return(receiver.DeadLetterAsync(receivedMessage.SystemProperties.LockToken, (IDictionary <string, object>)inboundBrokeredMessage.ApplicationProperties)); }
/// <summary> /// Routes a brokered message to a brokered message receiver responsible for compensating a received message /// </summary> /// <param name="inboundBrokeredMessage">The inbound brokered message to be routed to the compensation destination</param> /// <param name="transactionContext">The transaction information that was received with <paramref name="inboundBrokeredMessage"/></param> /// <param name="destinationRouterContext">The <see cref="CompensationRoutingContext"/> containing contextual information describing the compensating action</param> /// <exception cref="CompensationRoutingException">An exception containing contextual information describing the failure during compensation and routing details</exception> /// <returns>An awaitable <see cref="Task"/></returns> public Task Route(InboundBrokeredMessage inboundBrokeredMessage, TransactionContext transactionContext, CompensationRoutingContext destinationRouterContext) { if (destinationRouterContext is null) { //TODO: log return(Task.CompletedTask); } try { if (destinationRouterContext is null) { throw new ArgumentNullException(nameof(destinationRouterContext), $"A '{typeof(CompensationRoutingContext).Name}' is required to route a compensation message"); } if (string.IsNullOrWhiteSpace(destinationRouterContext.CompensateDetails)) { throw new ArgumentNullException(nameof(destinationRouterContext.CompensateDetails), $"A compensation reason is required to route a compensation message"); } if (string.IsNullOrWhiteSpace(destinationRouterContext.CompensateDescription)) { throw new ArgumentNullException(nameof(destinationRouterContext.CompensateDescription), $"A compensation description is required to route a compensation message"); } var outbound = OutboundBrokeredMessage.Forward(inboundBrokeredMessage, destinationRouterContext.DestinationPath) .WithFailureDetails(destinationRouterContext.CompensateDetails) .WithFailureDescription(destinationRouterContext.CompensateDescription) .SetFailure(); return(_router.Route(outbound, transactionContext)); } catch (Exception causeOfRoutingFailure) { throw new CompensationRoutingException(destinationRouterContext, causeOfRoutingFailure); } }
public CompensationRoutingException(CompensationRoutingContext compensateContext, Exception causeOfRoutingFailure) : base(compensateContext, causeOfRoutingFailure, "Routing message broker compensation message failed.") { _compensateContext = compensateContext ?? throw new ArgumentNullException(nameof(compensateContext), "A compensate context is required."); }