Request/Reply on error

Hi,

We are using callbacks (request/reply) together with the outbox.

In case something goes wrong in a (request) message handler, we would like to rollback all published messages, but we would still like to send a reply to the client. Tests show us that the reply is stored in the outbox, so rolling back the outbox transaction will also rollback the reply.

How can we send back the error to the client so that the request won’t hang until it times out?

I understand this must be difficult to combine this with retries. We have disabled retries for callbacks.

Thanks,
/Torbjörn

Hi Torbjörn,

If you need to send the response back to the caller when errors happen it often means that the error is relevant at the business level and should be explicitly handled in your logic. Can you share more information about your specific case?

The recoverability that ensures atomic message processing (publishing messages and sending the response in your scenario), is meant to handle infrastructural problems (likely solved by retries) or code bugs.

Cheers,
Tomek

Hi Tomek,

What do you mean by “explicitly handled in your logic”? Do you mean like asynchronously sending an error response to the client?

We are migrating from MSMQ and DTC to RabbitMQ with an outbox. We use the callback feature for legacy code that have a synchronous flow to get into a message handler context so we can have the outbox replace DTC.

Regarding retries (and moving to error queue) it doesn’t make sense for us for requests since they originate from the user. If the user doesn’t see the result of an action immediately, he will retry manually, so we don’t want NServiceBus to do it for him. Transient errors, like deadlocks, make more sense to retry (immediate), but for simplicity we have decided not to distinguish between errors.

/Torbjörn

Hi Torbjörn,

What do you mean by “explicitly handled in your logic”? Do you mean like asynchronously sending an error response to the client?

Recoverability handles message processing errors without surfacing them to the end-users. This is based on the assumption that recoverability handles errors that are caused by infrastructural problems.

If you need to expose the errors to the users you likely need to write the logic in the handler. I don’t know the details of our particular case but this could mean wrapping some parts into try-catch and publishing dedicated message when an exception gets thrown.

If the user doesn’t see the result of an action immediately, he will retry manually, so we don’t want NServiceBus to do it for him.

How is this handled in your current architecture (MSMQ and DTC)?

Tomek

Do not Send/Publish all messages. First create a collection of messages to send and store all message there until you are sure that you can send/publish these. Using the outbox doesn’t mean you can ‘rollback’ any messages. You can only rollback the whole transaction.

Further more, to send ‘replies’ in case of issues:

Replies participate in the handler transaction and are not sent if the message rolls back. If the code requires a response whether or not message processing succeeds, use immediate dispatch on the reply options. Make sure exceptions are rethrown to rollback any transactions and use a custom recoverability policy to not retry non-transient errors.

Source: https://docs.particular.net/nservicebus/messaging/reply-to-a-message|

You should also ask yourself why this is needed. In general, the advise is to not do querying via messaging.

Also, because you are doing both the publishing and response sending you might be doing to many things in a single handler. Check if maybe the handler can be redesigned and split into independant handlers.

Ramon and Tomek,

The RequireImmediateDispatch() is exactly what I was looking for. Don’t know how I’ve missed it, I’ve read that page a few times…

I realize a lot of our code is far from optimal. Using DTC it is far easier to get away with not doing things the way pub/sub is supposed to be done, and I guess that’s our excuse. Hopefully, using the outbox will also lead to a better design in future code.

Thanks for the help,
/Torbjörn