处理后台作业中的数据库调用失败

问题描述 投票:0回答:1

我有以下工作流程:

  1. UI 调用 API 来删除资源。此删除操作非常耗时,需要进行大量外部调用。因此,实际删除是作为异步/后台工作流程运行的。
  2. API 处理程序将 db 中资源的状态更改为
    Deleting
    ,启动后台进程并向调用者返回 ok。有一个单独的作业表来跟踪这些后台进程及其状态。
  3. UI会不断轮询svc来获取资源的当前状态。步骤2之后就是删除。如果一切顺利,后台进程将完成工作流程并将状态更改为
    Deleted
    ,或者如果出现错误,状态将变为
    DeleteFailed
    。此状态将反映在 UI 中。

注意:一旦状态为“正在删除”,UI 上的删除按钮将被禁用。如果删除失败,删除按钮会再次启用,调用者可以再次调用删除API

问题

如果后台线程执行期间出现 infra/db 故障,资源将永远处于

Deleting

状态。

解决方案

  • 基础设施故障

    - 在节点启动时添加了作业恢复代码(从主方法),它将检查是否有作业处于运行状态,如果有则重新运行作业。此处跳过实现细节。这已经解决了

  • 数据库调用失败

    - 在这种情况下,作业完成(可能是成功/失败),但数据库记录处于挂起状态(正在删除)。怎么解决这个问题?

    无法从 UI 进行另一个删除调用,因为“删除按钮”被禁用
    • 我能想到的唯一解决方案 - 有
    • 一个消毒/清理线程
    • ,定期扫描表中处于挂起状态的记录并清理它。
  • 想法?有更好的解决办法吗?应该有一些标准方法来解决这个问题,因为这似乎是一个常见问题。

asynchronous design-patterns architecture microservices jobs
1个回答
0
投票

确定你的“主人”,即控制整个操作的人。如果主设备本身没有状态,那么您需要有一个具有状态的状态主设备,最好是整个事物的第一个子部分。
  1. 整个操作的实际“原子”子部分是什么?这些子部分可以是不同的服务,像这样递归地处理它们的原子性。即使用他们自己的分阶段事务或单个原子数据库事务
  2. 一旦有了子部件,请查看所需的关联跟踪器状态。
  3. 一旦你有了这些,尝试看看你是否真的需要给定子部分的原子性。你能减少子部分的数量以使事情变得更简单吗?原子性越小或者不需要原子性王子部分越好。
  4. 一旦这些都存在,您需要执行“分阶段事务”,其中 master 处理其状态并跟踪它并尝试整个事情。
  5. 定义您的重试策略。理想情况下,您应该在子部分操作中进行几次内联重试,然后如果这不起作用,您需要中止那里的操作并稍后根据某些标准重试,即基础设施问题、数据库问题、需要手动干预等。
  6. 是否使用清理线程或“死信队列”进行“带外”重试。第二个需要在流程开始时进行额外的操作。
  7. 定义故障条件和/或报告/警报/手动干预所需条件,并在需要时执行此操作,即内联或带外。
  8. 在您的特定情况下,如果您的数据库故障发生在主服务器中,您可以执行原子事务并稍后将其检测为数据库提交故障。如果它位于子部分中并且您希望状态位于其本身中,那么该子部分将需要处理失败。

如果您没有有效地获得“卡住”操作的方法,那么执行扫描的清理线程可能不是一个好主意。在这种情况下,死信队列会更简单。

© www.soinside.com 2019 - 2024. All rights reserved.