如何处理DDD中的外部有状态Web服务?

时间:2019-01-28 12:34:43

标签: web-services domain-driven-design aggregate repository-pattern

场景1

  • 情况:我需要对Web服务中的某些数据执行业务操作。
  • 解决方案:存储库将Web服务用作存储库,使用Web服务数据构建聚合,并在以后保存更改。
  • 怀疑:这样可以吗?

场景#2

  • 情况:我需要对数据库中的某些数据执行业务操作,并且这种操作涉及用于计算值的Web服务。
  • 解决方案:Web服务被抽象为域服务,因此将其作为参数传递给聚合以执行操作。
  • 疑问:这有意义吗?我想说,Web服务应该是存储库的一部分,因此数据可以持久存储在一起。

场景#3

  • 情况:业务操作从/向两个不同的数据库请求数据/将数据保存到其中,一个数据库可以通过Web服务直接访问,另一个数据库。
  • 解决方案:数据库连接和Web服务都在存储库中,并且一起保存。聚合不知道该拆分。

场景4(问题开始...)

  • 情况:我需要对数据库中的数据执行一项涉及Web服务操作的业务操作,而业务操作本身需要该结果。
  • 问题:尽管Web服务是幂等的,但它不是事务性的,也不在我的控制之下。对Web服务的调用取决于聚合必须加载的某些数据,聚合逻辑取决于Web服务返回的结果代码(想象为在线支付)。
  • 解决方案:该Web服务用作域服务,如果请求失败,则一切都会失败,并且稍后会重试。如果数据库在保存时失败,则也会重试。

场景#n [#4的许多变体] ...

因此,我无法确定清楚如何使用DDD中的状态改变状态的Web服务的标准。

理想情况下,我将在存储中进行更改,然后使用某种集成层来复制外部数据库或服务中的更改,例如使用事件。但是,大多数情况下,存在写后读一致性要求,如果您在操作返回后刷新,则会在屏幕上显示正确的数据(例如:来自同一笔付款的Web服务的付款收据)

另一个示例:屏幕允许保存有关书籍的数据,但是书籍规格保存在数据库中,描述(几种语言)保存在外部服务中。操作必须一致,如果用户单击“保存”并刷新,则屏幕需要全部显示,不能仅显示具有旧翻译的规范,或者根本不显示翻译,因为它们已被复制到另一个数据库。

哪个是确定的标准?

2 个答案:

答案 0 :(得分:2)

答案是阅读Life Beyond Distributed Transactions

简短的形式是,尝试可靠地协调不同位置的写入非常昂贵。在大多数情况下,最好在您的设计中承认您不能一次到处都是,并投资于处理该事实的后果。

答案 1 :(得分:1)

我一直适用的规则是Aggregate应该是纯净的,不依赖于进行IO调用的服务(即磁盘或网络)。每次在给定状态下执行命令时,它应该给出相同的结果。在方法调用中注入服务或将其作为参数传递会破坏此规则。抽象的想法是聚合永远不要基于它不拥有的数据做出决定。

但是,每个复杂系统都包含多个集合。它还包含对业务流程进行建模的Sagas /流程经理(从现在开始就是Saga)。设计完美的Saga的所有需求就是一个清晰的业务流程和幂等的端点。

Saga开始,然后通常通过订阅Domain事件来侦听域中的更改。它通过将命令发送到相应的端点来对它们做出反应。请注意,我使用术语“端点”来指代任何以幂等方式处理命令的接收器。纯聚合就是这样的端点。但是Saga端点也可以是外部系统,例如支付网关。这样的网关不应使用现有的PaymentID(系统正在发送的不透明字段)来发起新的付款。

结论:据我了解,您所有的方案都可以实施为Sagas。

您可以了解有关Sagas hereherehere的更多信息。

相关问题