代理工作器协议#
系统架构#
系统由多个进程组成,每个进程要么是_服务_进程,要么是_工作器_进程。 工作器进程托管应用程序代码(代理)并连接到服务进程。 工作器向服务通告它们支持的代理,以便服务可以决定将代理放置在哪个工作器上。 服务进程协调代理在工作器进程上的放置,并促进代理之间的通信。
代理实例由元组 (namespace: str, name: str)
标识。
namespace 和 name 都由应用程序定义。
系统不对 namespace 施加任何语义:它是自由格式的,任何语义都由应用程序代码实现。
name 用于将请求路由到支持该名称的代理的工作器。
工作器向服务通告它们能够托管的代理名称集合。
工作器根据从服务接收的消息激活代理。
服务使用 name 来确定当前非活动代理的放置位置,维护从代理名称到支持该代理的工作器集合的映射。
服务维护一个_目录_,将活动代理 ID 映射到托管该代理的工作器进程。
代理生命周期#
代理永远不会被显式创建或销毁。当收到针对当前非活动代理的请求时,服务负责选择一个能够托管该代理的工作器,并将请求路由到该工作器。
工作器协议流程#
工作器协议有三个阶段,遵循工作器的生命周期:初始化、运行和终止。
初始化#
当工作器进程启动时,它启动与服务进程的连接,建立一个双向通信通道,用于传递消息。
接下来,工作器发出零个或多个 RegisterAgentType(name: str)
消息,告诉服务它能够托管的代理的名称。
待办:工作器应该向服务提供哪些其他元数据?
待办:我们是否应该给工作器一个唯一的 ID,可以用来在其生命周期内识别它?我们是否应该允许这个 ID 由工作器进程本身指定?
运行#
一旦建立连接,并且服务知道工作器能够托管哪些代理,工作器就可以开始接收它必须托管的代理的请求。
代理的放置是响应 Event(...)
或 RpcRequest(...)
消息而发生的。
工作器维护一个本地活动代理的_目录_:从代理 ID 到代理实例的映射。
如果收到针对目录中没有对应条目的代理的消息,工作器会激活该代理的新实例并将其插入目录。
工作器将消息分发给代理:
对于
Event
,代理处理消息,不生成响应。对于
RpcRequest
消息,代理处理消息并生成RpcResponse
类型的响应。工作器将响应路由回原始发送者。
工作器维护一个未完成请求的映射,通过 RpcRequest.id
标识,映射到未来 RpcResponse
的承诺。
当收到 RpcResponse
时,工作器找到相应的请求 ID 并使用该响应实现承诺。
如果在指定的时间范围内(例如,30秒)没有收到响应,工作器会以超时错误中断承诺。
终止#
当工作器准备关闭时,它关闭与服务的连接并终止。服务注销工作器和所有托管在其上的代理实例。