确认来自参与者链的 MQ 消息的正确方法是什么?

What is a proper way to acknowledge an MQ message from a chain of actors?

我们想使用 Akka 实现一个场景,即从消息队列 (RabbitMQ) 中获取消息,然后由一系列参与者进行处理。队列是持久的,消息不能丢失。所以我们需要向队列发送一个确认(RabbitMQ 中的 BasicAck)以完成出队消息。因此,处理链中的最后一个参与者需要进行确认。这似乎是相当普遍的需求,我想知道是否有一个已知的模式。 Vaughn Vernon 在他的书中写到使用 Return 地址,因此沿着链发送的所有消息都将具有 return 地址(MQ 通道参与者的)和指定队列消息标记的相关标识符。这是正确的做法吗?

另一种方法是在收到消息后立即确认消息,然后使用持久性 actor 来提供有保证的交付,但我被建议不要使用这种方法,因为使用 AMPQ 消除了对于这种特定场景的 actor 持久性的需要。

我不太熟悉 Akka,但我想我明白了它的作用(非常类似于 Erlang 中的 "process" - 我认为 - 这就是 RMQ 的构建基础)。

总的来说,Vaughn Vernon 书中的第一个建议就是要走的路。

在我的特定场景中,我对您的建议采取了 "middleware" 方法。我的特定中间件实现通过处理消息的命令链转发消息本身。每个命令调用一个action.next()方法继续转发到下一个命令。

在通过中间件发送消息之前,我创建了一个默认 last-command-in-the-chain。这个默认命令只是调用 actions.ack() - 它在幕后确认了消息。

我这样做是为了让命令永远不必知道如何实际实现完成和继续下一件事的机制。他们有一个特定于他们自己的 API ,是链中的命令。

这允许我更改确认消息的实现,或者我如何处理来自 RMQ 的消息等,而无需直接更改命令。

立即确认消息会带来危险,因为您的 actor 可能会崩溃,Akka 本身可能会崩溃,并且可能(并且将会)发生许多其他问题,并且您更有可能丢失消息。

请记住,没有 100% 完美的设置。在某些时候,您会丢失一条消息或处理同一条消息两次。您的系统需要在某个时刻以某种方式处理这些场景。您所做的一切都是朝着正确的方向前进,以减少这种可能性,但没有什么可以 100% 地防止崩溃和消息丢失。