【问题标题】:I'm struggling to understand the relationship between the UI and other Services in SOA我正在努力理解 UI 和 SOA 中其他服务之间的关系
【发布时间】:2015-04-28 22:19:07
【问题描述】:

免责声明:我真的才刚刚开始接触 SOA,所以您必须原谅我的无知。

我有一个非常简单的服务,可以处理来自 3rd 方 API(salesforce)的应用程序。 UI 接受 ID -> 发送 ProcessCmd 并启动 saga -> saga 从 API 导入数据 -> saga 订阅 ImportedEvt 并尝试验证 -> saga 无限期地运行检查新信息或手动覆盖 -> 如果 saga 结束,则发布带有状态的 ProcessedEvt。

现在我的 UI 是基于 Angular/SignalR 的两个页面。

  1. Index.html 在提交时填充了 ID 和空字段(通过 JS)并监听这两个事件。 ImportedEvt 填充一些字段,ProcessedEvt 填充状态字段(接受/拒绝等)。它还会激活指向详细信息的链接。

  2. Details.html 只是查询数据库。

最初我将数据保存在 ProcessingSaga 中,但我在 David Boike 的 book 中读到,这是不好的做法,因为 saga 是船长,只发出命令但没有实际的操舵。所以我在我的服务上添加了另一个 ProcessedEvtHandler 以保存到数据库,但我不知道这是否正确。

有几件事让我感到困惑:

  • 我记得 Udi 曾经说过,两个服务不应通过共享相同的数据而相互依赖。但我也明白 NServiceBus 不是为同步查询而设计的。因此,我必须在我的 UI 和我的服务之间在逻辑上共享相同的数据库。我可以理解仅 UI 查询是可以的,但就我而言,为了用户体验,我还想保存到数据库。
  • 因为我将数据库逻辑与我的 saga 分开,就像我被推荐的那样,我的事件失去了它们的自然顺序。我的 UI 很可能击败了 DB 调用,并且 details.html 暂时为空。我的两个事件 ImportedEvt 和 ProcessedEvt 反映了我的业务模型似乎是合乎逻辑的。在我看来,这些是唯一事件也是合乎逻辑的。为什么我应该纯粹为了 UI 而创建一个新事件 SavedToDbEvt?

在我看来,尽管我的 UI 有它自己的端点并且能够像任何其他服务一样发送/接收消息。它并不真正属于同一类别。拥有最终一致性对于幕后业务规则非常有用,但会产生糟糕的用户体验,我不明白我为什么不能让 UI 服务共享数据库?

我错过了什么吗?

【问题讨论】:

    标签: nservicebus soa


    【解决方案1】:

    如果两个物理服务/进程共享一个数据库,你基本上没有两个逻辑服务,你只有一个。这是 SOA 的基本原则。

    听起来您的 UI 和后端服务在物理上是分开的。即便如此,您可能想问自己它们是代表两个逻辑服务还是一个。如果它们代表相同的逻辑服务,那么让它们访问相同的数据库不会违反任何规则。

    如果它们代表两个逻辑服务(我怀疑它们确实如此),请考虑不要直接从 UI 查询数据库;而是通过某种形式的请求/响应(WebAPI、WCF 等)查询后端服务,并让 it 查询数据库。应通过从 UI 向后端服务发送命令来保存到数据库。命令通常应该是业务动词(例如“ChangeCustomerAddress”与“UpdateCustomer”)。

    我为什么要纯粹为了 UI 而创建一个新事件 SavedToDbEvt?

    我不确定我是否理解这部分问题。本质上,您应该在事情​​已经发生时发布事件。如果您正在处理保存到数据库的过程,则事件通常会在数据库提交成功后发布。这意味着您应该发布“SavedToDbEvt”之类的事件,但这可能意味着您的 ProcessedEvt 不应该在数据被持久化之前发布。

    编辑

    这是一个很好的问题,你在cmets中的后续问题也很合理。不幸的是,我们开始跨界进入可以使这个问题成为论坛更好的问题的领域,在那里可以进行来回讨论。我将在此处添加一些一般性的想法,但可能无法给出明确的答案,因为每种情况都是独一无二的,并且(可能)有不止一种解决方案可行。

    也许我正在创建比我真正需要的更多的层/服务。

    很难说不知道更多。 UI 会使用其他后端服务,还是仅使用您的问题所涉及的服务?另外,后端逻辑会被其他服务使用,还是仅仅被这个 UI 使用?如果它们在逻辑上是一个单元,那么您绝对应该考虑通过不将它们物理分布来简化您的设计。

    另一个抽象层(即 WCF)有助于弥合差距 [...]

    即使您使用的是事件驱动/总线式架构,也几乎总是需要对其他服务进行请求/响应式查询。举个简单的例子:如果您的 UI 服务是全新的,但您的后端服务已经部署多年怎么办? UI 将如何获取现有状态,因为它可能错过了后端服务已经发布的多年事件?

    虽然您可以通过 ESB 模拟请求/响应,但这并不是它的本意——在大多数情况下,我建议不要这样做。

    最后,听起来您确实需要在数据库保存完成后发布一个额外的事件。在我看来,当应用程序成为系统的永久部分时,它代表了一种有趣的状态变化。如果是这种情况,那么让业务感兴趣的状态变化是什么?如果您能弄清楚这一点,您的活动应该会开始变得更有意义,并且可能会自然地转化为比“SavedToDb”更好的名称!

    【讨论】:

    • 我仍然有些困惑,如何添加另一层抽象(即 WCF)有助于弥合最终一致性的异步“量子世界”与 UX/UI 要求的同步确定性需求之间的差距,因此在 ApplicationProcessed 事件之后我需要多余的 SavedToDb 事件。
    • 我认为我要解决的问题是我本能地将 UI 视为一种服务,而它可能只是一个服务的一部分的层。有一个单一的 MVC Web 项目是否可行,比方说,它有一个没有额外 WCF 层的总线端点?它会解决我的问题,但它只是让我感到厌烦,因为它似乎很紧凑。也许我正在创建比我真正需要的更多的层/服务。
    • 在我的回答中添加了一些额外的评论。
    猜你喜欢
    • 2020-08-10
    • 2020-06-12
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    • 2021-04-01
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多