How to handle message order in nservicebus?

2019-07-14 18:57发布

问题:

I'm trying to find a way to process messages in the order they were sent from the sender since NServiceBus does not guarantee that messages will be processed in a particular order.

The sender is an order system which publishes createOrder and reviseOrder commands. The sender allows the user to submit multiple revisions to the same order so there can be revision 4 and revision 3 in the queue at the same time. Each revision has a revision number and reason code associated with it which drives some business logic so we cannot ignore any revisions or at least the reason part of it.

A couple of ideas I had are listed below -

  1. Store the revision number with the destination record. The sender sends their revision number in each revision message. The handler compares the sender and destination revision numbers, if they match the record is updated else the message is put at the end of the queue. With this approach if revision 2 message fails and goes into the error queue revision 3 will never be processed.

  2. Sender sends the history of all reason codes for all revisions on every revision message. So if revision 2 message fails, revision 3 message will have all the reason codes. These reason codes will be recorded in the destination but any business logic associated with the previous revisions reason code may not occur.

How do we design for this scenario?
Also any ideas on how to handle the failed revision messages?

Some guidance is really appreciated.

Thanks.

回答1:

Out of the box one of the primary guidelines around NserviceBus is that you should build your systems in a way that order doesnt matter. Having said that i have built an ordered system with NSB before, heres how I decided to do it:

  • Add a sequence number to all messages
  • in the receiver check the sequence number is the last seen number + 1 if not throw an out of sequence exception
  • Enable second level retries (so if they are out of order they will try again later hopefully after the correct message was received)

This generally works pretty well, however sometimes stuff will go a bit out of whack if something is out of order for too long and manual intervention to resequence is required.

In your scenario there is probably a better way. Given you are only wanting ordering within the revisions which are made to orders. I think you can build this in a way that doesn't require ordered delivery.

  • Add a revision number to all the fields which you can modify with a revision
  • only update the field if the revision number in the message is >= the last revision in the db

This has a bunch of benefits.

  • It doesn't rely on order
  • It reduces load by only requiring the receiver to process each message once
  • it deals pretty well with errors by not stopping everything if there's an issue with a single message.

But it has the following drawbacks:

  • Added complexity in the db
  • Its eventually consistant, if you look at the db it may only contain some of the edits a user has done.
  • If rev2 errors and rev3 is processed correctly some of the users edits wont be there but some will