首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在事件源系统中建模聊天消息?

如何在事件源系统中建模聊天消息?
EN

Stack Overflow用户
提问于 2021-02-05 00:02:58
回答 1查看 436关注 0票数 1

上下文:我正在探索如何使用EventStoreDB (每个聚合单独的事件流)和Node.JS/TypeScript构建一个事件源系统/EventStoreDB。系统的一部分是1:1的客户支持聊天。创建聊天消息时,向用户发送推送通知,包括更新应用程序的标识号(未读消息总数)。我想知道什么是最好的方法来建模聚合/有界的上下文。

问题1:聊天消息放在哪里?

问题2:如何处理客户的未读邮件徽章计数器?

由于聊天消息本身已经是定时事件,它们似乎可以很容易地适应事件源系统。不过,我仍在寻求关于如何最好地对聚合体建模的建议:

选项A:由于每个聊天消息都有自己的生命周期(可以编辑它们,具有更新的读取状态,等等),所以ChatMessage可以是它自己的聚合。这会使聚合的数量激增(从而导致流),但对于EventStoreDB来说,这可能不是真正的问题。但是,要发送消息的通知,我们需要知道未读消息的总数(其他聚合的信息)。但是,推送通知应该如何发送"saga“/”流程管理器“(哪个是正确的术语?)知道通知要发送哪个警徽柜台吗?它是否应该根据所看到的所有事件为每个客户保留自己的状态/读取模型和当前计数器?

选项B:另一种方法可能是在客户聚合根目录下有一个消息列表。这样,客户就可以有一个未读消息数量的计数器,所有事件的折叠都会给我这个号码。但是,在这里,恐怕客户聚集根的大量聊天消息事件会妨碍“简单”的客户行为。例如,在处理customer命令时,我们首先通过折叠所有事件来获得当前状态(假设不使用快照),这意味着应用所有的聊天事件,甚至只是用客户的当前名称来做一些事情。

选项C:还是应该在不同的有界上下文中?那么,客户是否将其联系人详细信息放在有界的上下文中,并有一个单独的有界上下文用于聊天(或一般情况下的通信),其中两者都有一个客户聚合根共享,只共享客户的UUID?这是最好的两个世界,还是会带来其他挑战?

有什么选择吗?或者还有其他更好的选择?或者我只是完全忽略了这一点;) (不想排除这一点)

任何建议都非常感谢!

EN

回答 1

Stack Overflow用户

发布于 2021-02-23 20:17:55

event描述了一种(重新)创建状态的方法,方法是将每个更改存储为一个事件。这不包括这些事件是如何持久化或快照的,也不包括如何读取和分发这些事件。

我总是从用户界面开始。因为在那里您应该知道要显示哪些信息,以及可以执行哪些操作。

例如,可以有以下命令(或由用户界面执行的操作):

  • SendMessage(receiverId, content)

  • MarkMessageAsRead(messageId)

然后,服务器将检查所提供的数据是否有效,并创建相关事件:

代码语言:javascript
复制
class SupportChatMessageAggregate {
  MessageId messageId;
  UserId senderId;
  UserId receiverId;
  String content;
  boolean readByReceiver;

  // depending on framework and personal preference, this could
  // also be a method: handle(SendMessage command, CurrentUser currentUser)
  constructor(SendMessage command, CurrentUser currentUser) {
    validate(command); // throws Exception if invalid
    // for example if content is empty,
    // or if currentUser is not allowed to send messages to receiverId

    publishEvent(new MessageSentEvent(
      command.getMessageId(),
      currentUser.getUserId(),
      command.getReceiverId(),
      command.getContent()
    ));
  }

  handle(MarkMessageAsRead command, CurrentUser currentUser) {
    validate(command); // throws Exception if invalid
    // for example check if currentUser == receiver

    publishEvent(new MessageMarkedAsReadEvent(
      command.getMessageId(),
      currentUser.getUserId()
    ));
  }

  ...

}

现在,当您想知道用户的徽章计数器时,只需将所有的MessageSentEvents where = currentUser相加,并减去currentUser的所有MessageMarkedAsReadEvents。

例如,这可以在UnreadSupportChatMessageCountAggregate中完成,它负责根据给定用户的MessageSentEvents和MessageMarkedAsReadEvents提供当前的unreadMessages值。一个相当无聊的集合,但它完成了工作。

这就是事件源:您只是有一堆事件,如果您想查询一些数据,只需获取所有相关事件,处理它们,并获得结果。如果每个聚合使用单独的事件流,或者所有事件只有一个流,则是实现细节(或取决于您使用的事件存储)。

这取决于事件的数量,可以非常快,也可以非常慢。这就是快照和/或读取模型(来自CQRS)派上用场的地方。但是对于普通的事件源来说,这并不是必需的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66055683

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档