-
Notifications
You must be signed in to change notification settings - Fork 612
Description
Describe the bug
It seems that the async API layer does not allow access to the root cause of the error when using BasicPublic.
When BasicPublishAsync
fails (we call it here in our code) we get the following RabbitMQ.Client.Exceptions.PublishException
exception:
RabbitMQ.Client.Exceptions.PublishException: Exception of type 'RabbitMQ.Client.Exceptions.PublishException' was thrown.
at RabbitMQ.Client.Impl.Channel.PublisherConfirmationInfo.MaybeWaitForConfirmationAsync(CancellationToken cancellationToken)
at RabbitMQ.Client.Impl.Channel.MaybeEndPublisherConfirmationTracking(PublisherConfirmationInfo publisherConfirmationInfo, CancellationToken cancellationToken)
at RabbitMQ.Client.Impl.Channel.BasicPublishAsync[TProperties](String exchange, String routingKey, Boolean mandatory, TProperties basicProperties, ReadOnlyMemory`1 body, CancellationToken cancellationToken)
at NServiceBus.Transport.RabbitMQ.ConfirmsAwareChannel.SendMessage(String address, OutgoingMessage message, BasicProperties properties, CancellationToken cancellationToken) in /_/src/NServiceBus.Transport.RabbitMQ/Connection/ConfirmsAwareChannel.cs:line 38
at NServiceBus.Transport.RabbitMQ.MessageDispatcher.Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, CancellationToken cancellationToken) in /_/src/NServiceBus.Transport.RabbitMQ/Sending/MessageDispatcher.cs:line 48
at NServiceBus.Transport.RabbitMQ.MessageDispatcher.Dispatch(TransportOperations outgoingMessages, TransportTransaction transaction, CancellationToken cancellationToken) in /_/src/NServiceBus.Transport.RabbitMQ/Sending/MessageDispatcher.cs:line 52
at NServiceBus.TransportReceiveToPhysicalMessageConnector.Invoke(ITransportReceiveContext context, Func`2 next) in /_/src/NServiceBus.Core/Pipeline/Incoming/TransportReceiveToPhysicalMessageConnector.cs:line 67
at NServiceBus.RetryAcknowledgementBehavior.Invoke(ITransportReceiveContext context, Func`2 next) in /_/src/NServiceBus.Core/ServicePlatform/Retries/RetryAcknowledgementBehavior.cs:line 25
at NServiceBus.TracingExtensions.<>c__DisplayClass0_0`1.<<Invoke>g__TracePipelineStatus|0>d.MoveNext() in /_/src/NServiceBus.Core/OpenTelemetry/Tracing/TracingExtensions.cs:line 19
--- End of stack trace from previous location ---
at NServiceBus.MainPipelineExecutor.Invoke(MessageContext messageContext, CancellationToken cancellationToken) in /_/src/NServiceBus.Core/Pipeline/MainPipelineExecutor.cs:line 50
at NServiceBus.MainPipelineExecutor.Invoke(MessageContext messageContext, CancellationToken cancellationToken) in /_/src/NServiceBus.Core/Pipeline/MainPipelineExecutor.cs:line 78
at NServiceBus.Transport.RabbitMQ.MessagePump.Process(AsyncEventingBasicConsumer consumer, BasicDeliverEventArgs message, CancellationToken messageProcessingCancellationToken) in /_/src/NServiceBus.Transport.RabbitMQ/Receiving/MessagePump.cs:line 437
Notice, the exception's message property is Exception of type 'RabbitMQ.Client.Exceptions.PublishException' was thrown.
and there seem to be no dedicated properties on the exception object itself that would allow us to figure out what has happened.
Previously, we used BasicPublish
(equivalent place in our codebase) and handled the errors using BasicReturn
event:
void Channel_BasicReturn(object sender, BasicReturnEventArgs e)
{
var message = $"Message could not be routed to {e.Exchange + e.RoutingKey}: {e.ReplyCode} {e.ReplyText}";
if (e.BasicProperties.TryGetConfirmationId(out var deliveryTag))
{
SetException(deliveryTag, message);
}
else
{
Logger.Warn(message);
}
}
This resulted in a nice exception message that could be used to either diagnose the issue or make about the resolution strategy:
System.Exception: Message could not be routed to amq.rabbitmq.reply-to.g1h2AA9yZXBseUAxMzAwMzQ0MjAAAAVRAAAAAGgA9c8=.XqSncsOeQAvX+2A45bhwhA==: 312 NO_ROUTE
Reproduction steps
For the specific exception that we are dealing with:
- Create an exchange that is not bound to any queue
- When using sync API, subscribe to
BasicReturn
- Use
BasicPublish
to publish a message to that exchange and observe the event containing the details of the problem - When using API, call
BasicPublishAsync
to publish a message to that exchange and observePublishException
with no problem details available
Expected behavior
The message property on PublishException
contains the reason of the failure. What would be even better is dedicated properties on that exception type that contain more specific information.
Additional context
No response