连接运行时¶
Web、桌面渲染器和移动端在 packages/client-runtime 中按环境共享一个连接所有者。平台代码提供存储、凭据、网络信号和应用生命周期事件。React 视图消费该运行时。将重试和会话生命周期集中在这里,可防止多个视图需要同一环境时出现相互竞争的重连循环。
一个传输重试所有者¶
supervisor 拥有传输重试策略;解析端点和打开 RPC 会话都是单次尝试。瞬时故障使用带抖动的指数退避进行重试,上限为五分钟,且只有在连接持续在线后才会重置。没有抖动,重启服务器的每个客户端都会在同一秒重连;上限过短,永远无法连接的客户端会整天重试。离线状态和身份验证失败会等待唤醒,而不是在未改变的条件上消耗尝试次数。
进入前台、网络变化、显式重试和离线报告都会探测已建立的会话,只有探测失败才会重连。离线报告经常是错误的,例如对于回环服务器而言。操作系统可能会在不发送关闭事件的情况下杀死挂起的套接字,因此一个在 500 ms 后仍未得到应答的探测会通过新的请求询问主机的公共描述符,并且每秒重复一次,直到得到应答。如果主机做出了应答而套接字没有传递任何帧,则该套接字已失效并被替换,即使网络报告为离线也是如此:在回环和 LAN 上立即替换;在其他地方,则在检查开始 2.5 秒后替换,因为那里丢失一个数据包就可能导致活动套接字停滞。如果没有该证据,则由探测截止时间决定:在回环和 LAN 路由以及移动端长时间挂起后(此时屏幕上的数据已过时),截止时间为 3 秒;在其他地方为 15 秒,因为通过 DERP 或 VPN 的 tailnet 即使套接字是活动的,也可能比这更慢。长时间挂起的探测如果超时,也会替换套接字,无论网络报告如何。Web 和桌面端的前台探测会跳过新的请求,因为繁忙的主机可能会在排队探测之前应答它。进入前台还会立即唤醒挂起的重试。长时间挂起会重新开始进行中的尝试;短时间挂起则不会。
registry 按环境限定连接的作用域。非自愿断开会保留注册和缓存数据。显式移除会关闭作用域,并清除凭据、投影以及平台拥有的状态(如草稿)。云账户更改适用于中继注册;它们不得丢弃直接配对的环境。
HTTP 授权¶
RPC 会话在套接字升级时进行身份验证,而 HTTP 请求需要来自授权服务的当前凭据。为 HTTP 续期而替换健康的套接字会中断会话,并在没有传输故障的情况下更改传输代次。刷新失败属于 HTTP 操作本身。
当会话被撤销或过期时,服务器会关闭套接字。T3 Connect 访问令牌的有效期为一小时,因此驱动程序会在活动套接字令牌的最后一分钟为其续期。随后,服务器会将套接字移动到具有相同 DPoP 密钥、主体和作用域的较新会话(SessionStore.awaitInvalidation)。如果续期失败,套接字将在过期时关闭,并由 supervisor 重新连接。
会话列表必须在凭据过期后保留未被撤销的已连接会话,这样打开的连接不会从连接管理中消失。这并不会延长凭据的生命周期。新的 HTTP 请求和套接字升级仍然需要有效凭据。
传输健康与数据新鲜度是分开的¶
套接字打开并不是环境可用的充分证据。RPC 会话会等待初始服务器配置就绪后才变为可用。Shell 和线程数据随后拥有各自的同步状态。失败的 shell 订阅可以与健康连接共存;将这种状态标记为“正在重连”承诺了一次永远不会发生的传输重试。
缓存的投影在离线时仍可读取。它们既不能暗示存在活动连接,也不能在重连期间覆盖较新的实时数据。加载和恢复快照属于共享状态服务,因此每个视图都会就哪些数据是当前数据达成一致。
Shell 快照在客户端请求时可能会省略某些行。公布 shellThreadFamilies 的服务器会省略空闲的子代理子项:只要子项有活动或排队的运行、待处理的请求或后台工作,或者有属于自己的子代理子项,它就会保留,因此徽章和工作遍历绝不会遇到间隙。还公布 shellOlderSettled 的服务器只保留 25 个最新的已完结顶级线程(以及与第 25 个并列、被固定、被暂停、活跃或位于某个保留子项之上的任何线程);快照的 olderSettled 会指明这个截断点,并按项目统计其余线程。被省略的行会按需加载,并合并到 shell 行之后(线程族):线程视图或排队消息所挂载的族会保存共享该线程根的所有活动线程,因此它也能带回通过链接打开的旧已完结线程;“已完结”搁架读取截断点以下的页;搜索会返回较旧匹配项的行。因此,缺少 shell 行并不能证明线程已消失:在缺席时删除数据或工作树的代码必须先检查该族或服务器。
已完结计数是本地已完结行数,减去截断点以下的本地行数,再加上服务器的计数(更早的已完结线程)。当一次删除或旧行的到达或更改可能导致这些计数移动时,会重新读取它们,因此归档任何线程只需一次小读取。搁架只会在仍可加载的环境的最高页边界之上列出较旧的行,因此在页面加载期间,合并列表仍保持正确的前缀。如果某个环境在本会话中没有快照,或某页加载失败,则不会拖住任何人。按需读取会等待会话的第一个权威快照(generation > 0),并且每次读取都以 generation 为键。跳过了该快照的恢复流程在验证后仍必须递增 generation,并且只有在缓存的快照的遗漏与会话所要求的一致时,才能复用该缓存快照。
线程详情将订阅生命周期与缓存生命周期分离。已挂载的消费者共享一条实时流,当最后一个消费者卸载时,该流即停止;隐藏的已挂载路由仍计入其中。注册表本地缓存会将状态及其重放游标保留空闲五分钟,以便后退导航无需再次下载快照即可恢复。
桌面应用额外添加了一个消费者:一个 keep-alive 会在每个启用的环境中挂载每个会话正在启动或运行的线程。这样,打开正在运行的线程就无需重放。外壳流和详情流相互独立,因此外壳可以在详情加载完成或追上之前报告停止。已停止的线程会保持挂载,直到其自身流处于活动状态并显示停止,随后该流关闭并保存最终状态。 Web 和移动端不会保持线程存活。
只有在更新完成后,才将状态和游标一起保留。取消操作不得将缓存的游标推进到已应用数据之外,旧作用域也不得覆盖其继任者的缓存。复用时保留分页数据,但清除已取消的加载状态。
RPC 边界在执行时会针对当前会话解析请求。持久订阅会跟随接替的会话。传输故障后,它们会等待监督者;预期的领域故障可以在同一健康会话上重新订阅。重新连接不会自动重放变更,变更的重试和幂等性规则属于操作本身。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 t3/t3code