为了账号安全,请及时绑定邮箱和手机立即绑定

分布式系统中工作流错误处理——以Infinitic为例

在分布式系统中,由于在不同服务中可能出现的各种潜在问题,错误处理本质上来说相当复杂。通常,这需要团队实施复杂的追踪系统来监控和排查错误。

Infinitic 通过自动跟踪错误链,并且可以直接在工作流中处理错误,让整个失败处理变得更简单。

Infinitic 是一个为 Java/Kotlin 应用程序设计的 基于事件的流程编排框架。它允许你编写工作流,就像它们在单一服务器上运行一样,但实际上是在由 Apache Pulsar 支持的分布式、事件驱动架构上运行。

在发布版本 0.17.0 后,Infinitic 引入了强大的新功能,使管理工作流错误前所未有的容易。

  • 内置可靠性:无消息丢失,至少一次投递,优雅恢复
  • 自动重试瞬时失败
  • 自动将错误传递给父工作流
  • 工作流级别支持手动或自动错误处理
Infinitic 及工作流编排简介

Infinitic 是围绕 Apache Pulsar 构建的,Apache Pulsar 是一个分布式消息系统,确保组件间的消息可靠交换。Infinitic 中的任务由 服务执行器 处理,这些执行器处理特定领域的工作,比如库存管理、支付处理或用户管理。工作流,代表任务的高层次编排(例如完成订单),则由 工作流执行器 负责。

无论是服务执行器还是工作流执行器都具备水平扩展能力,这意味着可以添加额外的实例来处理增加的负载,从而确保系统的稳定性。然而,与任何分布式系统一样,错误可能在各个阶段发生,无论是由于 bug、网络问题、服务过载,还是人为交互的延迟或中断。这时,Infinitic 的错误管理功能就发挥作用了。

Pulsar 的通用保证

Infinitic 依靠 Pulsar 来确保可靠的消息传递基础架构,确保提供以下关键保证:

  • 无消息丢失:Pulsar 确保不会丢失任何消息。多区域集群甚至可以配置为缓解灾难性风险,例如该区域内所有消息日志的丢失。
  • 至少一次投递:虽然 Pulsar 通常会将每个消息准确地投递一次,但在某些罕见情况下,消息可能会被消费多次。
  • 从崩溃中平稳恢复:如果消费者(如服务或工作流执行器)因硬件问题或其他故障而崩溃,正在处理的消息将被释放,并最终被另一个实例消费。

这些保证构成了Infinitic确保任务和工作流可靠处理的基础,但比如任务或工作流失败时,又会发生什么呢?

处理瞬时失败

在任何分布式系统中,临时故障是非常常见的。这些故障可能包括网络问题、服务过载或临时的 API 停机。Infinitic 处理这些问题的方式是自动重试失败的任务。

这些重试是可以自定义的,并可以根据具体用例进行精确调整,提供了处理失败的灵活性,使失败的管理更加灵活。此外,Infinitic 提供了一个任务 ID,可以将其用作幂等密钥,用来确保幂等性,这对于确保任务不会被重复执行非常关键。

不过,重试不一定能让任务最终能够成功。因此,在工作流程中制定应对任务失败的策略非常重要。

工作流级错误处理

当一个Service Worker 在多次尝试后仍然无法处理任务时,Infinitic 会向请求的工作流任务发送一个错误消息。默认情况下,如果任务是同步请求,这将导致工作流失败。

相比之下,如果是异步请求的任务,那么失败不会立即引起工作流中的错误。

不过,如果工作流之后尝试获取某项失败的异步任务的结果,将引发异常:

在某些极端情况下——例如当 服务执行者 永久不可用或长时间不可用时——失败消息可能无法传递。为应对这种情况,Infinitic 允许用户在工作流层面设置超时。如果任务结果在指定时间内未返回,工作流将触发错误。

(请注意:超时的消息由Pulsar自己当作延迟消息来处理。)

手动错误处理步骤

当工作流因为异常而失败时,通常会按照以下流程处理:……

  1. DevOps 认知:该问题通过系统的日志机制被检测到。
  2. 问题解决:DevOps 决定如何解决根本原因(例如修复服务错误或增加资源)。
  3. 重试失败的作业:一旦问题被解决,DevOps 可以使用 Infinitic 客户端来重试失败的任务
  4. 自动恢复:任务成功后,工作流实例会自动从上次中断的地方继续执行。
使用 try...catch 进行自动错误处理功能

Infinitic 还支持自动处理错误,使得可以直接在工作流中处理任务失败。这在预期会出现失败的情形下特别有用,例如,某个产品暂时缺货。

你可以在一个工作流中使用 [try…catch](https://docs.infinitic.io/docs/workflows/errors#try-catch-in-workflows) 块来确保即使某个任务失败,流程也能继续执行。例如,在一个场景中,假设有一个任务名为 taskA,因业务限制而失败。通过用 try…catch 包裹该调用,可以确保即使 taskA 失败了,工作流也能继续。

    try {  
      TaskResult result = myService.taskA(data)  
    } catch (TaskFailedEception e) {  
      // 处理任务失败的情况  
      处理失败  
    }

这种方法提高了工作流程的灵活性和恢复力,使其能够更灵活地应对失败。

解决异步任务中的问题

正如之前提到的,异步任务不会立即导致工作流中的错误。然而,如果你想处理异步任务中的错误,你可以在子工作流中使用 try…catch 块来处理异步任务,或者在主工作流的其他部分使用 try…catch 块来处理。

这允许您在保持对主工作流程控制的同时异步地处理错误,请参阅文档

错误传递到父工作流任务或者客户端

当使用无穷状态时,也会自动将工作流中的异常传递给调用的工作流:

或者同步等待它的客户端应用程序:

此外,抛出的异常包含了导致当前状况的整个错误链的详尽信息。这为我们提供了一个深入了解根本原因并采取适当行动的机会,如有必要。

最后

Infinitic的强大错误管理能力简化了在分布式系统中处理故障的过程。通过自动重试瞬时错误、跟踪错误并提供灵活的工作流配置,Infinitic确保复杂的工作流保持可靠、灵活且具有弹性。

无论您选择手动处理错误,还是利用Infinitic自带的自动错误处理功能,该平台都提供了高度灵活的错误管理方式,使构建和维护容错系统更简单。

我们鼓励您试试Infinitic,这样更口语化。无论您是开发新功能还是优化现有系统,Infinitic 提供所需的工具,而不会增加复杂性。为了获取定期更新、最佳实践和深入教程,可以考虑订阅我们的 Substack,这样语气更自然。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消