如何处理未能响应成功但成功提交到数据库的消息

How to handle message that failed to response success, but success commit to database

我有一些关于处理未能响应成功但成功提交到数据库的消息的问题。

我认为的设计是为了保证处理消息一次。
以下顺序为处理步骤。
问题包含在带有 ★

的语句中

1) 从消息队列中获取消息
-> 在此之后失败时,MQ 将超时并重试

2) Cache.SetIfNotExist(MessageId, MyId, 超时)
处理时间 < Cache.Timeout < MQ.Timeout
* 这使消息拥有所有权
-> 在此之后失败时,Cache 将超时,MQ 将超时并重试

3) 处理数据包括读取存储
* 所有数据都应该包含乐观锁信息
-> 在此之后失败时,Cache 将超时,MQ 将超时并重试

4) Cache.Get(MessageId) == MyId
* 这确认该处理器拥有消息的所有权
-> 在此之后失败时,Cache 将超时,MQ 将超时并重试

5) 提交数据
* 这会将所有数据提交到存储
* 如果更新多个文档,乐观锁不保证一致性(如果存在all or nothing特性,可以获得一致性保证)
* 如果你在乐观锁定状态下使用某些文档进行读取,读取文档和提交文档应该通过乐观锁定检查
* 你应该在 RDBMS 中使用事务来保证一致性
★ 这是问题后失败。如果 MQ 重试此事务,则无法检查。所以交易将被处理两次或更多次。
★ 如果提交数据时缓存超时,也会出现同样的问题。

6) Cache.Set(MessageId, MyId, 超时)
* 在删除消息之前防止 MQ 超时重试。

7) 确认消息
* 发送完成并从消息队列中删除消息

感谢您的阅读。

我发现如果数据库不保存问题中描述的消息 ownersnip 数据,则无法解决此问题。
在数据库中,恢复机制恢复删除崩溃的数据,如提交但不会在停机后结束事务。
解决这种情况的一种方法是在提交阶段失败时将阶段标志添加到所有权缓存检查数据库。
另一种方法是更新数据库,知道已发布的 messageid 过期,并通过定期批处理删除它。
只有一个线程写作业可以保证一致性,或者需要其他机制。所以服务到数据库通信有两个线程,它不能保证。