我们需要按照到达 MSMQ 的顺序处理所有消息。
请参阅此问题的答案How to handle message order in nservicebus? ,还有这个帖子在这里。
我同意虽然可以按订单交付,但最好设计您的系统,使订单无关紧要。链接的文章概述了以下解决方案:
- 为所有消息添加序列号
- 在接收器中检查序列号是最后看到的数字+ 1,如果没有抛出乱序异常
- 启用二级重试(因此,如果它们出现故障,他们希望在收到正确消息后稍后再试)
但是,为了回答您的具体问题:
在这种情况下,设置 MaximumConcurrencyLevel="1" MaximumMessageThroughputPerSecond="1" 会有所帮助吗?
并不真地。
每当您需要按顺序交付时,基本的逻辑法则规定,在您的消息处理管道的某处,您必须有一个单线程进程以保证按顺序交付。
发生这种情况取决于您(查看重新排序器模式),但您当然可以将 NserviceBus 处理程序限制为单个线程(我认为您不需要设置 MaximumMessageThroughputPerSecond 以使其成为单线程)。
但是,即使您这样做了,并且即使您使用了事务队列,您仍然不能保证每条消息都会出队并按顺序处理到数据库中,因为如果任何消息出现任何永久性故障,它们将是从队列中删除并处理下一条消息。
在数据库停机期间,我们希望进程重试 MSMQ 中的第一条消息并停止处理其他消息,直到数据库启动。一旦数据库启动,我们希望 NServicebus 按照发送消息的顺序进行处理。
不建议这样做。NServiceBus 中的第二级重试功能旨在处理意外和短期中断,而不是计划和长期中断。
对于初学者,当您的 NServiceBus 消息处理程序端点尝试处理其输入队列中的消息并发现数据库不可用时,它将执行其第二级重试策略,默认情况下将尝试出队 5 次,频率增加,然后永久失败,将失败的消息粘贴到它的错误队列中。然后它将移动到输入队列中的下一条消息。
虽然这本身并不违反您的按订单交付要求,但由于两个原因,这会使生活变得非常困难:
- 一旦数据库再次可用,将需要优先重新处理永久失败的消息,并且
- 会有大量不需要的故障日志记录,这将混淆任何真正的处理错误。
如果您提前知道定期计划的中断,那么处理它们的最简单方法是实施服务窗口,这是计划的另一个术语。
但是,Windows 服务管理器不支持服务窗口的概念,因此您必须使用计划任务来停止然后启动您的服务,或者查看其他选项,例如hangfire、quartz.net或其他一些cron 类型的库。