代理工作器协议#

系统架构#

系统由多个进程组成,每个进程要么是_服务_进程,要么是_工作器_进程。 工作器进程托管应用程序代码(代理)并连接到服务进程。 工作器向服务通告它们支持的代理,以便服务可以决定将代理放置在哪个工作器上。 服务进程协调代理在工作器进程上的放置,并促进代理之间的通信。

代理实例由元组 (namespace: str, name: str) 标识。 namespacename 都由应用程序定义。 系统不对 namespace 施加任何语义:它是自由格式的,任何语义都由应用程序代码实现。 name 用于将请求路由到支持该名称的代理的工作器。 工作器向服务通告它们能够托管的代理名称集合。 工作器根据从服务接收的消息激活代理。 服务使用 name 来确定当前非活动代理的放置位置,维护从代理名称到支持该代理的工作器集合的映射。 服务维护一个_目录_,将活动代理 ID 映射到托管该代理的工作器进程。

代理生命周期#

代理永远不会被显式创建或销毁。当收到针对当前非活动代理的请求时,服务负责选择一个能够托管该代理的工作器,并将请求路由到该工作器。

工作器协议流程#

工作器协议有三个阶段,遵循工作器的生命周期:初始化、运行和终止。

初始化#

当工作器进程启动时,它启动与服务进程的连接,建立一个双向通信通道,用于传递消息。 接下来,工作器发出零个或多个 RegisterAgentType(name: str) 消息,告诉服务它能够托管的代理的名称。

  • 待办:工作器应该向服务提供哪些其他元数据?

  • 待办:我们是否应该给工作器一个唯一的 ID,可以用来在其生命周期内识别它?我们是否应该允许这个 ID 由工作器进程本身指定?

运行#

一旦建立连接,并且服务知道工作器能够托管哪些代理,工作器就可以开始接收它必须托管的代理的请求。 代理的放置是响应 Event(...)RpcRequest(...) 消息而发生的。 工作器维护一个本地活动代理的_目录_:从代理 ID 到代理实例的映射。 如果收到针对目录中没有对应条目的代理的消息,工作器会激活该代理的新实例并将其插入目录。 工作器将消息分发给代理:

  • 对于 Event,代理处理消息,不生成响应。

  • 对于 RpcRequest 消息,代理处理消息并生成 RpcResponse 类型的响应。工作器将响应路由回原始发送者。

工作器维护一个未完成请求的映射,通过 RpcRequest.id 标识,映射到未来 RpcResponse 的承诺。 当收到 RpcResponse 时,工作器找到相应的请求 ID 并使用该响应实现承诺。 如果在指定的时间范围内(例如,30秒)没有收到响应,工作器会以超时错误中断承诺。

终止#

当工作器准备关闭时,它关闭与服务的连接并终止。服务注销工作器和所有托管在其上的代理实例。