9.4. 例子


例如,您需要订购一个新顺序,且您的系统中有两个不同的服务:一个用于管理该订单和一个管理学分。如果您有足够的分数,则可以在逻辑上放置一个订单。借助 Saga EIP,您可以采用 Sag y 路由作为由两种不同操作的 Saga 组成,一个用于创建顺序,另一个用于获取学分。必须执行这两个操作,否则 没有学分的订单都不能被视为不一致的结果(以及没有订单付款)。

from("direct:buy")
  .saga()
    .to("direct:newOrder")
    .to("direct:reserveCredit");
Copy to Clipboard Toggle word wrap

购买操作不会更改其他示例。用于对新订单和 Reserve credit 操作进行建模的不同选项如下:

from("direct:newOrder")
  .saga()
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:cancelOrder")
    .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
    .bean(orderManagerService, "newOrder")
    .log("Order ${body} created");
Copy to Clipboard Toggle word wrap

这里的传播模式被设置为 MANDATORY 意味着此路由中的任何交换流都必须是 Saga 的一部分(本例中为 Saga),因为 Saga 是在 direct:buy 路由中创建的 SANDATORY。direct:newOrder 路由声明了一个称为 direct:cancelOrder 的补偿操作,负责撤销 Saga 取消的顺序。

每个交换始终包含一个 Exchange.SAGA_LONG_RUNNING_ACTION 标头,此处用作订单的 ID。这标识了在相应的compensating 操作中删除的顺序,但这不是一个要求(选项可以作为替代解决方案使用)。direct:newOrder 的补偿操作为 direct:cancelOrder,它如下所示:

from("direct:cancelOrder")
  .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
  .bean(orderManagerService, "cancelOrder")
  .log("Order ${body} cancelled");
Copy to Clipboard Toggle word wrap

当应该取消订单时,Saga EIP 实施将自动调用。它不会遇到错误。如果在 direct:cancelOrder 路由中引发错误,则 EIP 实施应定期重试,以对特定限制执行相关的操作。这意味着,任何补偿操作都必须是幂等的,因此应该考虑多次触发它,且不应在任何情况下失败。如果在所有重试重试后无法进行补偿,则 Saga 实施中应该会触发手动干预流程。

注意

这可能是因为直接执行 直接:newOrder 路由造成的延迟导致,该 Saga 被代表另一个方取消(因为并行路由或 Saga 级别上的超时)存在错误。因此,当 compensating action direct:cancelOrder 被调用时,它无法找到被取消的 Order 记录。为了保证完全全局一致性,为了保证全局一致性,任何主要操作及其相应的补偿措施都是相互作用,例如,如果补偿在主要操作之前发生,则它应该具有相同的效果。

另一种可能的方法是,如果无法使用组合行为,则始终会在强制操作中失败,直到找到由主要操作生成的数据(或者重试次数上限)。这种方法可能在许多环境中工作,但是它很 深远

该信贷服务几乎按照与订购服务相同。

from("direct:reserveCredit")
  .saga()
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:refundCredit")
    .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
    .bean(creditService, "reserveCredit")
    .log("Credit ${header.amount} reserved in action ${body}");
Copy to Clipboard Toggle word wrap

调用compensation 操作:

from("direct:refundCredit")
  .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
  .bean(creditService, "refundCredit")
  .log("Credit for action ${body} refunded");
Copy to Clipboard Toggle word wrap

此处为信用预订提供补偿操作,即退款。

9.4.1. 处理完成事件

Saga 完成后,需要一些类型的处理。当发生错误并且 Saga 被取消时,会调用补救端点。当 Saga 成功完成时,可以调用完成端点 以执行进一步处理。例如,在以上订购服务中,我们需要知道订单已完成(保留的信用卡)以实际准备顺序。如果没有付款,我们并不想开始准备订单(与大多数现代 CPU 相同),在确保您是否有权阅读它前,我们不会让您访问保留内存的现代 CPU。这可以通过修改的 direct:newOrder 端点轻松完成:

  1. 调用完整端点:
from("direct:newOrder")
  .saga()
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:cancelOrder")
  .completion("direct:completeOrder")
    .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
    .bean(orderManagerService, "newOrder")
    .log("Order ${body} created");
Copy to Clipboard Toggle word wrap
  1. direct:cancelOrder 与上例中的相同。调用成功完成,如下所示:
from("direct:completeOrder")
  .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
  .bean(orderManagerService, "findExternalId")
  .to("jms:prepareOrder")
  .log("Order ${body} sent for preparation");
Copy to Clipboard Toggle word wrap

完成 Saga 后,订单将发送到 JMS 队列,以进行准备。与补偿操作类似,Saga 协调器可能会多次调用完成操作(特别是出现错误,如网络错误)。在本例中,侦听 prepareOrder JMS 队列的服务已准备好保存可能的重复(请参阅 Idempent Consumer EIP)以了解如何处理重复的示例。

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat