支持多个虚拟聊天室(例如使用 NServiceBus)

Supporting multiple virtual chatrooms (e.g. with NServiceBus)

我刚刚开始大量阅读有关服务总线架构的文章,并更仔细地研究了 NServiceBus 框架。我真的不知道如何设计多个私人上下文,其中一组客户对同一消息的副本感兴趣(例如聊天室应用程序)。

服务总线应该只存在一次,还是我会创建多个服务总线实例,每个虚拟聊天室一个,并为每个感兴趣的客户端订阅一个消息处理程序实例?

这是否与我已经在 Azure 上下文中阅读过的主题和订阅的概念有关?

Is the service bus supposed to exist only once or would I create multiple service bus instances, one for each virtual chatroom, and subscribe a message handler instance for each interested client?

使用 NServiceBus 时,您将为创建的每个 endpoint 配置一个总线。您可以将端点视为处理某些消息的服务。端点不是动态的,它们需要指定一个名称,以便其他端点可以配置为向它们发送消息或从它们接收消息。

这取决于您的系统要求,但我假设 虚拟聊天室 是您可以动态生成的东西 and/or不再使用。

Does it have something to do with the concept of topics and subscribes which I already read about in the context of Azure?

NServiceBus 和 Azure 服务总线都提供基础结构来完成 pub/sub。

I am not really getting an idea on how to design multiple private contexts where a set of clients are interested in the copies of the same message

多个私有上下文到底是什么意思?我理解你的问题是如何在客户和聊天室之间建立关系。您的描述中缺少的部分是持久性,即存储客户端和聊天室之间的关系。

以 NServiceBus 为例,您可以有一个 ClientService 来处理有关客户端采取的任何操作的消息,以及一个 ChatroomService 来处理有关聊天室内发生的操作的消息。然后工作流程可以去:

  1. 客户端进入聊天室(客户端向客户端发送命令)
  2. ClientService向Client对象添加信息并更新(持久化​​)
  3. ClientService 向 ChatroomService 发送命令以更新与相应聊天室关联的客户端列表。 (命令)
  4. 聊天室服务更新订阅客户列表(持久性)
  5. 另一个客户端在聊天室中创建了一个 Post。 (客户端向 ClientService 发送命令)
  6. ClientService 使用新的 Post 和创建它的客户端的 ID 以及它被发送到的聊天室的 ID 向 ChatroomService 发送命令(命令)
  7. ChatroomService 将 Post 添加到相应聊天室的 Posts 列表中(持久性)
  8. ChatroomService 为订阅相应聊天室(发布)的列表中的所有其他客户端生成事件
  9. ClientService 处理 ChatroomService 引发的事件并将 Post 分发给其他订阅的客户端。 (订阅)

我还没有真正创建过聊天室应用程序,因此这可能不是最适合您的想法的设计,但它提供了一种描述如何使用 NServiceBus 来创建应用程序的方法。您可以使用处理与系统中对象对应的消息的端点来设置服务。使用这种或类似的设计,您可以分离关注点,并可以根据每个对象类型必须处理的流量按需扩展您的服务。

编辑以根据评论中的问题添加更具体的示例

注意:将 text message 的所有引用更改为 Post 以便 NServiceBus 中 chat messageIMessage 之间没有歧义。我一直在故意使用术语 commandevent。在NServiceBus中,ICommand是一种只能发送给1个端点的消息,而IEvent是一种可以被多个端点发布和订阅的消息。

如果示例不清楚,我们深表歉意。我想表达的是,你可以存储 Clients 和 Chatrooms 之间的关系,这样当 Chatroom 得到一个新的 Post 时,它可以分发给只有与它相关的 Clients。假设您有一个聊天室 CR 和 3 个客户端 ABC,它们都在 CR 中。另外,假设我们有以下 类:

class Chatroom
{
    Guid Id { get; set; }
    List<Client> Subscribers { get; set; }
    List<Posts> Posts { get; set; }
}


class Client
{
    Guid Id { get; set; }
    List<Chatroom> Chatrooms { get; set; }
    ConnectionInfo Info { get; set; }
}

class Post
{
    Guid Id { get; set; }
    Guid ClientId { get; set; }
    Guid ChatroomId { get; set; }
    string Text { get; set; } 
}

class NewPostCommand : ICommand
{
    Post NewPost { get; set; }
}

class NewChatroomPostEvent : IEvent
{
    Post NewPost { get; set; }
    Chatroom Chatroom { get; set; }
    List<Client> Subscribers { get; set; }
}
  1. A 创建一个 PostCR,这是使用从客户端到 API 的 HTTP 调用实现的。 API 是充当 ClientService 的 NServiceBus 服务的一部分。 API 调用创建了一个包含文本 A.IdCR.Id.
  2. Post
  3. ClientService 使用刚刚创建的 PostNewPostCommand 发送到 ChatroomService
  4. ChatroomService 接收 NewPostCommand 并将其传递给适当的处理程序。
  5. 处理程序在 Post 上使用 ChatroomId 在您的数据库中搜索相应的 Chatroom (CR)。新 Post 添加到 CR.Posts 并更新数据库。
  6. 处理程序从 CR 中获取 CR.Clients 减去 Post.ClientId 的列表(导致 BC)。
  7. Handler 发布了一个新的 NewChatroomPostEvent,其中包含 PostChatroomSubscribers
  8. ClientService 订阅 NewChatroomPostEvent,接收消息并将其传递给适当的处理程序。
  9. ClientService 具有与客户端通信的所有功能(使用 Client.Info)并将新的 Post 发送到 NewChatroomPostEvent.Subscribers 列表中的每个客户端(BC).

现在我们已经了解了新 post 的消息流,您可以想象如何在每个聊天室中添加和删除订阅者。客户端在进入或离开聊天室时会向 HTTP API 发送消息,ClientService 会向 ChatroomService 发送消息,后者会更新相应的 Chatroom.Subscribers 列表。希望这能阐明您如何控制在新 post 到达时向哪些客户端发送更新。