首页 文章

在CQRS中验证与其他域相关的命令

提问于
浏览
1

我正在学习使用DDD,CQRS和ES开发微服务 . 它是HTTP RESTful服务 . 微服务是关于网上商店 . 有几个领域,如产品,订单,供应商,客户等 . 这些域构建在单独的服务中 . 如果命令有效负载与其他域相关,如何进行验证?

例如,这是订单服务(命令端)中的addOrderItemCommand有效负载 .

{
"customerId": "CUST111", 
"productId": "SKU222",
"orderId":"SO333"
}

如何验证上面的命令?如何知道客户真的存在于数据库(查询端客户服务)中并仍然活跃?如何知道产品是否存在于数据库中并且产品的状态是否已发布?如何知道客户是否有资格从相关产品中获得促销价?

是否可以直接调用API(如点对点/ ajax /请求承诺)来在命令端服务中验证此有效负载?但我认为,如果API直接调用验证,性能会变差 . 因为,我们在命令服务之外开发了一个事件处理器,它从事件中侦听并将事件应用于materalized视图 .

谢谢 .

2 回答

  • 2

    由于需要查询多个有界上下文以便验证通过,因此需要考虑最终的一致性 . 话虽如此,整个过程总有可能在“小”的时间内处于无效状态 . 例如,在接受命令之后和订单发货之前,可以停用用户 . 在线商店是一个复杂的系统,例外可能出现在任何子系统中 . 但是,作为事件驱动系统实施有助于;每次订购过程进入无效状态,您都可以采取补偿措施/命令 . 例如,如果在此期间停用用户,则可以取消其所有常规订单,发布预留产品,宣布愿望清单中没有这些产品的潜在客户等等 .

    DDD中有许多种验证,但我遵循一般规则,即验证应尽早完成,但不会影响数据的一致性 . 因此,为了尽早,您可以查询readmodel以拒绝无法生效的命令,并且为了使系统保持一致,您需要在订单发货之前进行另一次检查 .

    现在让我们谈谈您的具体问题:

    如何知道客户真的存在于数据库(查询端客户服务)中并且仍然有效?

    您可以查询readmodel以验证用户是否存在且仍处于活动状态 . 您应该这样做,因为来自无效用户的命令是某种攻击的强烈指示,并且您不希望这些命令通过您的系统 . 但是,即使命令通过此检查,也不一定意味着订单将被发送,因为其间可能会引发其他异常 .

    如何知道产品是否存在于数据库中并且产品的状态是否已发布?

    同样,您可以查询readmodel以通知用户此产品目前不可用 . 或者,根据您的业务,如果您知道这些产品将在不到24小时内根据以前的某些统计信息(例如您知道电视机每天都会在您的库存中到达),则可以允许该命令通过 . 或者您可以让客户选择是否等待 . 在这种情况下,如果产品在订购的最后阶段(发货)没有库存,则通知客户产品不再有库存 .

    如何知道客户是否有资格从相关产品中获得促销价?

    您可能需要查询另一个有界上下文,如 Promotions BC 来检查这一点 . 这取决于如何验证/使用促销 .

    是否可以直接调用API(如点对点/ ajax /请求承诺)以在命令端服务中验证此有效负载?但我认为,如果API直接调用验证,性能会变差 .

    这取决于您希望系统恢复的弹性以及拒绝无效命令的速度 .

    同步调用更容易实现,但它们会导致系统弹性降低(您应该注意级联故障并使用circuit breaker之类的技术来阻止它们) .

    异步(即使用事件)调用更难实现,但会使系统更具弹性 . 为了进行异步调用, ordering 系统可以为其他系统订阅事件并维护一个私有状态,可以在命令到达时查询以进行验证 . 通过这种方式,即使链接到 inventorycustomer management 系统已关闭,订购系统仍继续工作 .

    无论如何,这实际上取决于您的业务,我们都不能告诉您exaclty该做什么 .

  • 0

    一如既往,一切都取决于域的具体情况,但作为一般原则,跨域验证应通过读取模型完成 .

    在这种情况下,我会在每个微服务中维护一个读模型以用于验证 . 当然,这带来了最终一致性的问题 . 你如何处理这应该来自你对域的理解 . 应考虑诸如最终一致性的长度与更新频率之间的因素 . 与开发成本相比,将业务弄错的成本最小化问题 . 在许多情况下,只记录存在问题的事实对于企业来说已经足够了 .

    我有一篇专门用于验证的博客文章,您可以在这里找到:How To Validate Commands in a CQRS Application

相关问题