- Notifications
You must be signed in to change notification settings - Fork615
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.
WhenBasicPublishAsync fails (we call ithere in our code) we get the followingRabbitMQ.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 437Notice, the exception's message property isException 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 usedBasicPublish (equivalentplace in our codebase) and handled the errors usingBasicReturn event:
voidChannel_BasicReturn(objectsender,BasicReturnEventArgse){varmessage=$"Message could not be routed to{e.Exchange+e.RoutingKey}:{e.ReplyCode}{e.ReplyText}";if(e.BasicProperties.TryGetConfirmationId(outvardeliveryTag)){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_ROUTEReproduction 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
BasicPublishto publish a message to that exchange and observe the event containing the details of the problem - When using API, call
BasicPublishAsyncto publish a message to that exchange and observePublishExceptionwith no problem details available
Expected behavior
The message property onPublishException 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