我正在设计一些事件,这些事件将在系统中执行操作或数据更改时引发。这些事件可能会被许多不同的服务使用,并将被序列化为 XML,尽管更广泛地说,我的问题也适用于 Webhooks 等更现代的时髦事物的设计。
我正在特别考虑如何描述事件的变化,并且很难在不同的实现之间进行选择。让我来说明一下我的困惑。
假设创建了一个客户,并引发了一个简单的事件。
<CustomerCreated>
<CustomerId>1234</CustomerId>
<FullName>Bob</FullName>
<AccountLevel>Silver</AccountLevel>
</CustomerCreated>
现在假设鲍勃花了很多钱并成为黄金客户,或者实际上发生了任何其他属性(property)变化(例如:他现在更喜欢被称为罗伯特)。我可以发起这样的事件。
<CustomerModified>
<CustomerId>1234</CustomerId>
<FullName>Bob</FullName>
<AccountLevel>Gold</AccountLevel>
</CustomerModified>
这很好,因为 Created 和 Modified 事件的架构是相同的,并且任何订阅者都会收到实体的完整当前状态。然而,任何接收者都很难在不跟踪状态本身的情况下确定哪些属性已更改。
然后我想到了这样一个事件。
<CustomerModified>
<CustomerId>1234</CustomerId>
<AccountLevel>Gold</AccountLevel>
</CustomerModified>
这更加紧凑,仅包含已更改的属性,但缺点是接收者必须应用更改并在需要时重新组装实体的当前状态。此外,Created 和 Modified 事件的模式现在必须不同; CustomerId
是必需的,但所有其他属性都是可选的。
然后我想出了这个。
<CustomerModified>
<CustomerId>1234</CustomerId>
<Before>
<FullName>Bob</FullName>
<AccountLevel>Silver</AccountLevel>
</Before>
<After>
<FullName>Bob</FullName>
<AccountLevel>Gold</AccountLevel>
</After>
</CustomerModified>
这涵盖了所有基础,因为它包含完整的当前状态,而且接收器可以找出发生了什么变化。 Before
和 After
元素与 Created 事件具有完全相同的架构类型。然而,它非常冗长。
我一直在努力寻找任何好的事件示例;我还应该考虑其他模式吗?
最佳答案
您将问题标记为“事件溯源”,但您的问题似乎更多是关于事件驱动的 SOA。
我同意@Matt 的回答——如果客户会因为多种业务原因而改变,“CustomerModified”的粒度不足以捕获意图。
但是,我会进一步支持并要求您考虑为什么要将客户信息存储在本地服务中,而您(大概)似乎已经拥有客户的真实来源。使用客户信息的起点应该是在需要时从源获取它。存储可以从源可靠地查询的信息副本很可能是不必要的优化(和复杂化)。
即使您确实需要在本地存储客户数据(并且确实有必要这样做),请考虑仅传递构建事实来源查询(发出事件的服务)所需的数据:
<SomeInterestingCustomerStateChange>
<CustomerId>1234</CustomerId>
</SomeInterestingCustomerStateChange>
因此,这些事件类型可以根据需要分割,例如“CustomerAddressChanged”或简称“CustomerChanged”,消费者可以根据事件类型查询所需的信息。
不存在“一刀切”的解决方案——有时通过事件传递相关数据确实更有意义。再次,如果这是您需要前进的方向,我同意@Matt 的回答。
根据评论进行编辑
我同意使用 ESB 进行查询通常不是一个好主意。有些人以这种方式使用 ESB,但恕我直言,这是一种不好的做法。
您原来的问题以及您对此答案和马特的谈话的评论仅包括已更改的字段。这在许多语言中肯定会出现问题,您必须以某种方式区分属性为空/空和属性未包含在事件中。如果事件从/到静态类型进行序列化/反序列化,那么了解“名字被设置为 NULL”和“名字丢失,因为它没有”之间的区别将是痛苦的(如果不是不可能的话)不要改变”。
根据您关于系统同步的评论,我的建议是发送每次更改的完整数据集(假设信号+查询不是一个选项)。这将数据的解释留给每个消费系统,并限制发布者发出更通用事件的责任,即“客户 1234 已修改为 X 状态”。此事件似乎比其他选项更有用,如果其他系统收到此事件,他们可以按照自己认为合适的方式解释它。他们可以为客户 1234 转储/重写自己的数据,或者可以将其与他们拥有的数据进行比较并仅更新更改的数据。仅发送更改的内容对于单个消费者或特定类型的消费者来说似乎更具体。
尽管如此,我认为您提出的任何解决方案都不是“正确”或“错误”。您最了解什么最适合您的独特情况。
关于events - 通知事件的设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33254734/