コード例 #1
0
        public async Task Send(SagaConsumeContext <TInstance, TData> context, IPipe <SagaConsumeContext <TInstance, TData> > next)
        {
            var eventContext = new StateMachineEventContextProxy <TInstance, TData>(context, _machine, context.Saga, _event, context.Message);

            StartedActivity?activity = LogContext.IfEnabled(OperationName.Saga.RaiseEvent)
                                       ?.StartSagaActivity(context, (await _machine.Accessor.Get(eventContext).ConfigureAwait(false)).Name);

            try
            {
                await _machine.RaiseEvent(eventContext).ConfigureAwait(false);

                if (await _machine.IsCompleted(context.Saga).ConfigureAwait(false))
                {
                    await context.SetCompleted().ConfigureAwait(false);
                }
            }
            catch (UnhandledEventException ex)
            {
                State <TInstance> currentState = await _machine.Accessor.Get(eventContext).ConfigureAwait(false);

                throw new NotAcceptedStateMachineException(typeof(TInstance), typeof(TData), context.CorrelationId ?? Guid.Empty, currentState.Name, ex);
            }
            finally
            {
                activity?.AddTag(DiagnosticHeaders.EndState, (await _machine.Accessor.Get(eventContext).ConfigureAwait(false)).Name);
                activity?.Stop();
            }
        }
コード例 #2
0
        public async Task Send(ConsumeContext <RoutingSlip> context, IPipe <ConsumeContext <RoutingSlip> > next)
        {
            StartedActivity?activity = LogContext.IfEnabled(OperationName.Courier.Compensate)?.StartCompensateActivity <TActivity, TLog>(context);

            var timer = Stopwatch.StartNew();

            try
            {
                CompensateContext <TLog> compensateContext = new HostCompensateContext <TLog>(context);

                LogContext.Debug?.Log("Compensate Activity: {TrackingNumber} ({Activity}, {Host})", compensateContext.TrackingNumber,
                                      TypeMetadataCache <TActivity> .ShortName, context.ReceiveContext.InputAddress);

                try
                {
                    await Task.Yield();

                    await _compensatePipe.Send(compensateContext).ConfigureAwait(false);

                    var result = compensateContext.Result
                                 ?? compensateContext.Failed(new ActivityCompensationException("The activity compensation did not return a result"));

                    await result.Evaluate().ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await compensateContext.Failed(ex).Evaluate().ConfigureAwait(false);
                }

                await context.NotifyConsumed(timer.Elapsed, TypeMetadataCache <TActivity> .ShortName).ConfigureAwait(false);

                await next.Send(context).ConfigureAwait(false);
            }
            catch (OperationCanceledException exception)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TActivity> .ShortName, exception).ConfigureAwait(false);

                if (exception.CancellationToken == context.CancellationToken)
                {
                    throw;
                }

                throw new ConsumerCanceledException($"The operation was canceled by the activity: {TypeMetadataCache<TActivity>.ShortName}");
            }
            catch (Exception ex)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TActivity> .ShortName, ex).ConfigureAwait(false);

                LogContext.Error?.Log(ex, "Activity {Activity} compensation faulted", TypeMetadataCache <TActivity> .ShortName);

                throw;
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #3
0
        public async Task Dispatch(ReceiveContext context, ReceiveLockContext receiveLock = default)
        {
            LogContext.Current = _logContext;

            var active = StartDispatch();

            StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Receive)?.StartReceiveActivity(context);

            try
            {
                if (_observers.Count > 0)
                {
                    await _observers.PreReceive(context).ConfigureAwait(false);
                }

                if (receiveLock != null)
                {
                    await receiveLock.ValidateLockStatus().ConfigureAwait(false);
                }

                await _receivePipe.Send(context).ConfigureAwait(false);

                await context.ReceiveCompleted.ConfigureAwait(false);

                if (receiveLock != null)
                {
                    await receiveLock.Complete().ConfigureAwait(false);
                }

                if (_observers.Count > 0)
                {
                    await _observers.PostReceive(context).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                if (_observers.Count > 0)
                {
                    await _observers.ReceiveFault(context, ex).ConfigureAwait(false);
                }

                if (receiveLock != null)
                {
                    await receiveLock.Faulted(ex).ConfigureAwait(false);
                }

                throw;
            }
            finally
            {
                activity?.Stop();

                await active.Complete().ConfigureAwait(false);
            }
        }
コード例 #4
0
        async Task ISendTransport.Send <T>(T message, IPipe <SendContext <T> > pipe, CancellationToken cancellationToken)
        {
            LogContext.SetCurrentIfNull(_context.LogContext);

            var context = new MessageSendContext <T>(message, cancellationToken);

            await pipe.Send(context).ConfigureAwait(false);

            StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Send)?.StartSendActivity(context);

            try
            {
                if (_context.SendObservers.Count > 0)
                {
                    await _context.SendObservers.PreSend(context).ConfigureAwait(false);
                }

                var messageId = context.MessageId ?? NewId.NextGuid();

                var transportMessage = new InMemoryTransportMessage(messageId, context.Body, context.ContentType.MediaType,
                                                                    TypeMetadataCache <T> .ShortName)
                {
                    Delay = context.Delay
                };

                SetHeaders(transportMessage.Headers, context.Headers);

                await _context.Exchange.Send(transportMessage, cancellationToken).ConfigureAwait(false);

                context.LogSent();
                activity.AddSendContextHeadersPostSend(context);

                if (_context.SendObservers.Count > 0)
                {
                    await _context.SendObservers.PostSend(context).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                context.LogFaulted(ex);

                if (_context.SendObservers.Count > 0)
                {
                    await _context.SendObservers.SendFault(context, ex).ConfigureAwait(false);
                }

                throw;
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #5
0
            public async Task Send(ClientContext context)
            {
                LogContext.SetCurrentIfNull(_context.LogContext);

                await _context.ConfigureTopologyPipe.Send(context).ConfigureAwait(false);

                var sendContext = new TransportAmazonSqsSendContext <T>(_message, _cancellationToken);

                await _pipe.Send(sendContext).ConfigureAwait(false);

                StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Send)?.StartSendActivity(sendContext);

                try
                {
                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PreSend(sendContext).ConfigureAwait(false);
                    }

                    var request = await context.CreatePublishRequest(_context.EntityName, sendContext.Body).ConfigureAwait(false);

                    _context.SnsSetHeaderAdapter.Set(request.MessageAttributes, sendContext.Headers);

                    _context.SnsSetHeaderAdapter.Set(request.MessageAttributes, "Content-Type", sendContext.ContentType.MediaType);
                    _context.SnsSetHeaderAdapter.Set(request.MessageAttributes, nameof(sendContext.CorrelationId), sendContext.CorrelationId);

                    await context.Publish(request, sendContext.CancellationToken).ConfigureAwait(false);

                    sendContext.LogSent();
                    activity.AddSendContextHeadersPostSend(sendContext);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PostSend(sendContext).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    sendContext.LogFaulted(ex);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.SendFault(sendContext, ex).ConfigureAwait(false);
                    }

                    throw;
                }
                finally
                {
                    activity?.Stop();
                }
            }
コード例 #6
0
        public async Task Send(SagaConsumeContext <TSaga, TMessage> context, IPipe <SagaConsumeContext <TSaga, TMessage> > next)
        {
            StartedActivity?activity = LogContext.IfEnabled(OperationName.Saga.InitiateOrOrchestrate)?.StartSagaActivity(context);

            try
            {
                await context.Saga.Consume(context).ConfigureAwait(false);

                await next.Send(context).ConfigureAwait(false);
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #7
0
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            if (!context.TryGetPayload(out MessageSessionContext sessionContext))
            {
                throw new SagaException($"The session-based saga repository requires an active message session: {TypeMetadataCache<TSaga>.ShortName}",
                                        typeof(TSaga), typeof(T));
            }

            if (Guid.TryParse(sessionContext.SessionId, out var sessionId))
            {
                context = new CorrelationIdConsumeContextProxy <T>(context, sessionId);
            }

            StartedActivity?activity = LogContext.IfEnabled(OperationName.Saga.Send)?.StartSagaActivity <TSaga, T>(context);

            try
            {
                var saga = await ReadSagaState(sessionContext).ConfigureAwait(false);

                if (saga == null)
                {
                    var missingSagaPipe = new MissingPipe <T>(next, WriteSagaState);

                    await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
                }
                else
                {
                    SagaConsumeContext <TSaga, T> sagaConsumeContext = new MessageSessionSagaConsumeContext <TSaga, T>(context, sessionContext, saga);

                    LogContext.Debug?.Log("SAGA:{SagaType}:{CorrelationId} Used {MessageType}", TypeMetadataCache <TSaga> .ShortName,
                                          context.CorrelationId, TypeMetadataCache <T> .ShortName);

                    await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                    if (!sagaConsumeContext.IsCompleted)
                    {
                        await WriteSagaState(sessionContext, saga).ConfigureAwait(false);

                        LogContext.Debug?.Log("SAGA:{SagaType}:{CorrelationId} Updated {MessageType}", TypeMetadataCache <TSaga> .ShortName,
                                              context.CorrelationId, TypeMetadataCache <T> .ShortName);
                    }
                }
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #8
0
        async Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            StartedActivity?activity = LogContext.IfEnabled(OperationName.Saga.SendQuery)?.StartSagaActivity <TSaga, TMessage>(context);

            var timer = Stopwatch.StartNew();

            try
            {
                if (_queryFactory.TryCreateQuery(context, out ISagaQuery <TSaga> query))
                {
                    await Task.Yield();

                    await _sagaRepository.SendQuery(context, query, _policy, _messagePipe).ConfigureAwait(false);

                    await context.NotifyConsumed(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName).ConfigureAwait(false);
                }

                await next.Send(context).ConfigureAwait(false);
            }
            catch (OperationCanceledException exception)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName, exception).ConfigureAwait(false);

                if (exception.CancellationToken == context.CancellationToken)
                {
                    throw;
                }

                throw new ConsumerCanceledException($"The operation was canceled by the consumer: {TypeMetadataCache<TSaga>.ShortName}");
            }
            catch (Exception ex)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName, ex).ConfigureAwait(false);

                throw;
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #9
0
        async Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            StartedActivity?activity = LogContext.IfEnabled(OperationName.Consumer.Handle)?.StartHandlerActivity(context);

            var timer = Stopwatch.StartNew();

            try
            {
                await Task.Yield();

                await _handler(context).ConfigureAwait(false);

                await context.NotifyConsumed(timer.Elapsed, TypeMetadataCache <MessageHandler <TMessage> > .ShortName).ConfigureAwait(false);

                Interlocked.Increment(ref _completed);

                await next.Send(context).ConfigureAwait(false);
            }
            catch (OperationCanceledException exception)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <MessageHandler <TMessage> > .ShortName, exception).ConfigureAwait(false);

                if (exception.CancellationToken == context.CancellationToken)
                {
                    throw;
                }

                throw new ConsumerCanceledException($"The operation was canceled by the consumer: {TypeMetadataCache<MessageHandler<TMessage>>.ShortName}");
            }
            catch (Exception ex)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <MessageHandler <TMessage> > .ShortName, ex).ConfigureAwait(false);

                Interlocked.Increment(ref _faulted);
                throw;
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #10
0
        async Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            StartedActivity?activity = LogContext.IfEnabled(OperationName.Consumer.Consume)?.StartConsumerActivity <TConsumer, TMessage>(context);

            var timer = Stopwatch.StartNew();

            try
            {
                await Task.Yield();

                await _instancePipe.Send(new ConsumerConsumeContextScope <TConsumer, TMessage>(context, _instance)).ConfigureAwait(false);

                await context.NotifyConsumed(timer.Elapsed, TypeMetadataCache <TConsumer> .ShortName).ConfigureAwait(false);

                await next.Send(context).ConfigureAwait(false);
            }
            catch (OperationCanceledException exception)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TConsumer> .ShortName, exception).ConfigureAwait(false);

                if (exception.CancellationToken == context.CancellationToken)
                {
                    throw;
                }

                throw new ConsumerCanceledException($"The operation was canceled by the consumer: {TypeMetadataCache<TConsumer>.ShortName}");
            }
            catch (Exception ex)
            {
                await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TConsumer> .ShortName, ex).ConfigureAwait(false);

                throw;
            }
            finally
            {
                activity?.Stop();
            }
        }
コード例 #11
0
            public async Task Send(SessionContext sessionContext)
            {
                LogContext.SetCurrentIfNull(_context.LogContext);

                await _context.ConfigureTopologyPipe.Send(sessionContext).ConfigureAwait(false);

                var destination = await sessionContext.GetDestination(_context.EntityName, _context.DestinationType).ConfigureAwait(false);

                var producer = await sessionContext.CreateMessageProducer(destination).ConfigureAwait(false);

                var context = new TransportActiveMqSendContext <T>(_message, _cancellationToken);

                await _pipe.Send(context).ConfigureAwait(false);

                StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Send)?.StartSendActivity(context);

                try
                {
                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PreSend(context).ConfigureAwait(false);
                    }

                    var transportMessage = sessionContext.Session.CreateBytesMessage();

                    transportMessage.Properties.SetHeaders(context.Headers);

                    transportMessage.Properties["Content-Type"] = context.ContentType.MediaType;

                    transportMessage.NMSDeliveryMode = context.Durable ? MsgDeliveryMode.Persistent : MsgDeliveryMode.NonPersistent;

                    if (context.MessageId.HasValue)
                    {
                        transportMessage.NMSMessageId = context.MessageId.ToString();
                    }

                    if (context.CorrelationId.HasValue)
                    {
                        transportMessage.NMSCorrelationID = context.CorrelationId.ToString();
                    }

                    if (context.TimeToLive.HasValue)
                    {
                        transportMessage.NMSTimeToLive = context.TimeToLive > TimeSpan.Zero ? context.TimeToLive.Value : TimeSpan.FromSeconds(1);
                    }

                    if (context.Priority.HasValue)
                    {
                        transportMessage.NMSPriority = context.Priority.Value;
                    }

                    transportMessage.Content = context.Body;

                    var publishTask = Task.Run(() => producer.Send(transportMessage), context.CancellationToken);

                    await publishTask.OrCanceled(context.CancellationToken).ConfigureAwait(false);

                    context.LogSent();
                    activity.AddSendContextHeadersPostSend(context);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PostSend(context).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    context.LogFaulted(ex);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.SendFault(context, ex).ConfigureAwait(false);
                    }

                    throw;
                }
                finally
                {
                    activity?.Stop();
                }
            }
コード例 #12
0
            public async Task Send(ModelContext modelContext)
            {
                LogContext.SetCurrentIfNull(_context.LogContext);

                await _context.ConfigureTopologyPipe.Send(modelContext).ConfigureAwait(false);

                var properties = modelContext.Model.CreateBasicProperties();

                var context = new BasicPublishRabbitMqSendContext <T>(properties, _context.Exchange, _message, _cancellationToken);

                await _pipe.Send(context).ConfigureAwait(false);

                var exchange = context.Exchange;

                if (exchange.Equals(RabbitMqExchangeNames.ReplyTo))
                {
                    if (string.IsNullOrWhiteSpace(context.RoutingKey))
                    {
                        throw new TransportException(context.DestinationAddress, "RoutingKey must be specified when sending to reply-to address");
                    }

                    exchange = "";
                }

                StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Send)?.StartSendActivity(context);

                try
                {
                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PreSend(context).ConfigureAwait(false);
                    }

                    byte[] body = context.Body;

                    if (context.TryGetPayload(out PublishContext publishContext))
                    {
                        context.Mandatory = context.Mandatory || publishContext.Mandatory;
                    }

                    properties.Headers ??= new Dictionary <string, object>();

                    properties.ContentType = context.ContentType.MediaType;

                    properties.Headers["Content-Type"] = context.ContentType.MediaType;

                    SetHeaders(properties.Headers, context.Headers);

                    properties.Persistent = context.Durable;

                    if (context.MessageId.HasValue)
                    {
                        properties.MessageId = context.MessageId.ToString();
                    }

                    if (context.CorrelationId.HasValue)
                    {
                        properties.CorrelationId = context.CorrelationId.ToString();
                    }

                    if (context.TimeToLive.HasValue)
                    {
                        properties.Expiration = (context.TimeToLive > TimeSpan.Zero ? context.TimeToLive.Value : TimeSpan.FromSeconds(1)).TotalMilliseconds
                                                .ToString("F0", CultureInfo.InvariantCulture);
                    }

                    if (context.RequestId.HasValue && (context.ResponseAddress?.AbsolutePath?.EndsWith(RabbitMqExchangeNames.ReplyTo) ?? false))
                    {
                        context.BasicProperties.ReplyTo = RabbitMqExchangeNames.ReplyTo;
                    }

                    var publishTask = modelContext.BasicPublishAsync(exchange, context.RoutingKey ?? "", context.Mandatory, context.BasicProperties, body,
                                                                     context.AwaitAck);

                    await publishTask.OrCanceled(context.CancellationToken).ConfigureAwait(false);

                    context.LogSent();
                    activity.AddSendContextHeadersPostSend(context);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PostSend(context).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    context.LogFaulted(ex);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.SendFault(context, ex).ConfigureAwait(false);
                    }

                    throw;
                }
                finally
                {
                    activity?.Stop();
                }
            }
コード例 #13
0
            public async Task Send(ClientContext context)
            {
                LogContext.SetCurrentIfNull(_context.LogContext);

                await _context.ConfigureTopologyPipe.Send(context).ConfigureAwait(false);

                var sendContext = new TransportAmazonSqsSendContext <T>(_message, _cancellationToken);

                await _pipe.Send(sendContext).ConfigureAwait(false);

                StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Send)?.StartSendActivity(sendContext);

                try
                {
                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PreSend(sendContext).ConfigureAwait(false);
                    }

                    var message = new SendMessageBatchRequestEntry("", Encoding.UTF8.GetString(sendContext.Body));

                    _context.SqsSetHeaderAdapter.Set(message.MessageAttributes, sendContext.Headers);

                    _context.SqsSetHeaderAdapter.Set(message.MessageAttributes, "Content-Type", sendContext.ContentType.MediaType);
                    _context.SqsSetHeaderAdapter.Set(message.MessageAttributes, nameof(sendContext.CorrelationId), sendContext.CorrelationId);

                    if (!string.IsNullOrEmpty(sendContext.DeduplicationId))
                    {
                        message.MessageDeduplicationId = sendContext.DeduplicationId;
                    }

                    if (!string.IsNullOrEmpty(sendContext.GroupId))
                    {
                        message.MessageGroupId = sendContext.GroupId;
                    }

                    if (sendContext.DelaySeconds.HasValue)
                    {
                        message.DelaySeconds = sendContext.DelaySeconds.Value;
                    }

                    await context.SendMessage(_context.EntityName, message, sendContext.CancellationToken).ConfigureAwait(false);

                    sendContext.LogSent();
                    activity.AddSendContextHeadersPostSend(sendContext);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.PostSend(sendContext).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    sendContext.LogFaulted(ex);

                    if (_context.SendObservers.Count > 0)
                    {
                        await _context.SendObservers.SendFault(sendContext, ex).ConfigureAwait(false);
                    }

                    throw;
                }
                finally
                {
                    activity?.Stop();
                }
            }
コード例 #14
0
        async Task ISendTransport.Send <T>(T message, IPipe <SendContext <T> > pipe, CancellationToken cancellationToken)
        {
            LogContext.SetCurrentIfNull(_context.LogContext);

            var context = new TransportGrpcSendContext <T>(_context.Exchange.Name, message, cancellationToken);

            await pipe.Send(context).ConfigureAwait(false);

            StartedActivity?activity = LogContext.IfEnabled(OperationName.Transport.Send)?.StartSendActivity(context);

            try
            {
                if (_context.SendObservers.Count > 0)
                {
                    await _context.SendObservers.PreSend(context).ConfigureAwait(false);
                }

                var messageId = context.MessageId ?? NewId.NextGuid();

                var transportMessage = new TransportMessage
                {
                    Deliver = new Deliver
                    {
                        Exchange = new ExchangeDestination
                        {
                            Name       = _context.Exchange.Name,
                            RoutingKey = context.RoutingKey ?? ""
                        },
                        Envelope = new Envelope
                        {
                            MessageId          = messageId.ToString("D"),
                            RequestId          = context.RequestId?.ToString("D") ?? "",
                            ConversationId     = context.ConversationId?.ToString("D") ?? "",
                            CorrelationId      = context.CorrelationId?.ToString("D") ?? "",
                            InitiatorId        = context.InitiatorId?.ToString("D") ?? "",
                            SourceAddress      = context.SourceAddress?.ToString() ?? "",
                            DestinationAddress = context.DestinationAddress?.ToString() ?? "",
                            ResponseAddress    = context.ResponseAddress?.ToString() ?? "",
                            FaultAddress       = context.FaultAddress?.ToString() ?? "",
                            ContentType        = context.ContentType?.MediaType ?? "",
                            Body           = ByteString.CopyFrom(context.Body),
                            EnqueueTime    = context.Delay.ToFutureDateTime(),
                            ExpirationTime = context.TimeToLive.ToFutureDateTime(),
                            SentTime       = Timestamp.FromDateTime(context.SentTime ?? DateTime.UtcNow),
                        }
                    }
                };

                transportMessage.Deliver.Envelope.MessageType.AddRange(TypeMetadataCache <T> .MessageTypeNames);

                SetHeaders(transportMessage.Deliver.Envelope.Headers, context.Headers);

                var grpcTransportMessage = new GrpcTransportMessage(transportMessage, HostMetadataCache.Host);

                await _context.Exchange.Send(grpcTransportMessage, cancellationToken).ConfigureAwait(false);

                context.LogSent();
                activity.AddSendContextHeadersPostSend(context);

                if (_context.SendObservers.Count > 0)
                {
                    await _context.SendObservers.PostSend(context).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                context.LogFaulted(ex);

                if (_context.SendObservers.Count > 0)
                {
                    await _context.SendObservers.SendFault(context, ex).ConfigureAwait(false);
                }

                throw;
            }
            finally
            {
                activity?.Stop();
            }
        }