Appearance
Session 生命周期
本文档定义 Croupier shared session runtime 的最小生命周期模型,重点统一:
- session 状态
- 状态切换条件
drain的状态机语义SDK <-> Agent与Agent <-> Server的共同行为约束
本文档描述的是运行时模型,不是具体某个语言 SDK 的 API 细节。
目标
这份状态机文档要解决三个问题:
- 什么叫“session 已建立”
- 什么叫“session 正在 drain”
- 连接断开、重连、宽限关闭时,双方分别该做什么
最小状态集合
v1 建议统一使用下面几个核心状态:
connectinghandshakingactivedrainingclosedreconnecting
说明:
connecting- 底层连接正在建立
handshaking- 连接已建立,但首帧握手和会话注册尚未完成
active- session 可正常收发业务请求
draining- session 不再接收新业务请求,但允许排空在途请求
closed- 当前 session 已终止,不再可用
reconnecting- 旧 session 已终止,运行时正在等待或尝试建立新连接
状态机总览
text
connecting
|
v
handshaking
|
v
active ---------> draining ---------> closed
| ^ |
| | |
+--------------------+ |
connection lost / fatal |
v
reconnecting
|
v
connecting补充说明:
active -> draining是优雅摘流路径active -> closed是直接关闭路径draining -> closed是排空完成或宽限期结束closed -> reconnecting只适用于启用了自动重连的一方
各状态允许的行为
connecting
允许:
- 建立底层
tcp连接 - 初始化读写循环
- 启动建连超时
不允许:
- 发送业务请求
- 接收业务分发
handshaking
允许:
- 发送首帧握手消息
- 协商
session_id、协议版本与能力 - 验证首帧
MsgID与 protobuf body
不允许:
- 把连接当作可用业务 session
- 分配
Invoke / Task / Ops
进入 active 的前提是:
- 握手成功
- 获得有效
session_id - 本端运行时完成 in-flight 表初始化
active
允许:
- 双向发送 request/response
- 多个并发 in-flight 请求复用
- heartbeat
- 背压与过载反馈
- 接收
drain信号
这是唯一一个允许接收新业务请求分配的状态。
draining
这是最容易实现歧义的状态,定义如下:
- session 仍然存活
- heartbeat 仍然继续
- 控制消息仍然可以收发
- 已在途请求允许继续执行
- 不再向该 session 分配新的业务请求
允许:
- 完成已在途请求
- 返回最后一批 response / event
- 继续处理 session 级控制消息
- 在需要时返回
draining/retry_after_ms
不允许:
- 接收新的业务分发
- 把该 session 重新视为普通可用节点
closed
含义:
- 当前 session 已完全失效
- 旧
session_id不可继续使用 - 该连接上的未完成请求应被判定为失败、取消或失效
reconnecting
允许:
- 按退避策略等待
- 重新发起连接
- 重新进入
connecting
不允许:
- 复用旧
session_id - 假定旧 in-flight 会自动恢复
drain 状态机
drain 不是单独的一条控制命令而已,它对应的是 active -> draining -> closed 这条运行时路径。
触发条件
典型触发条件:
- 节点准备发布或退出
- 节点准备切换到新 session
- 节点过载,决定不再接新请求
- 运维侧主动执行摘流
进入 draining 时必须发生的事
当 session 从 active 进入 draining,运行时至少需要完成:
- 标记
draining = true - 停止向该 session 分配新的业务请求
- 保留 heartbeat
- 保留 in-flight 跟踪
- 启动可选的
drain grace timeout
draining 期间的行为
在 draining 期间:
- 已发出的请求可以继续完成
- 新来的业务请求应被拒绝、重路由或明确告知稍后重试
- 不应再把该 session 参与正常调度权重
退出 draining 的条件
退出 draining 只允许两种结果:
- 排空完成,进入
closed - 宽限时间结束,强制关闭后进入
closed
v1 不建议支持:
draining -> active
原因是这会引入更多实现复杂度和调度歧义。
如果未来确实需要“取消摘流”,应通过新 session 重建,而不是把旧 session 再改回 active。
在两条链路中的映射
SDK <-> Agent
当 provider session 进入 draining:
Agent不再向该 provider 分配新的Invoke / Task- provider 继续完成已接收的请求
ProviderDrainResponse只表示“已接受 drain 状态”- 排空完成后,连接可被优雅关闭
Agent <-> Server
当 agent session 进入 draining:
Dispatcher不再向该 session 路由新的Invoke / Task / OpsAgent继续完成已接收的工作- registry / 调度层应将该 session 视为“可排空,不可接新单”
- 排空完成后再移除该 session
失败与异常路径
不是所有关闭都走 drain。
以下情况通常直接进入 closed:
- 首帧非法
- 协议版本不兼容
- 认证失败
- 底层连接断开
- 致命编解码错误
这些路径不要求先进入 draining。
in-flight 请求处理规则
当 session 关闭时,必须明确旧 in-flight 的处理原则:
- response 已返回的请求正常完成
- 未返回的请求应被标记为失败或取消
- 不允许在新 session 上隐式继承旧 in-flight
如果未来要做幂等恢复,应通过明确的请求级设计实现,而不是把 session 重连当成隐式恢复。
观测与指标建议
建议至少暴露以下运行时指标:
- 当前状态
session_iddraininginflight_countqueued_request_countlast_heartbeat_atdrain_started_atdrain_deadline_atreconnect_attempt
这样排障时才能判断:
- 它是真的死了
- 还是正在优雅摘流
- 还是正在退避重连
测试建议
最小测试集至少包括:
- 建连成功后进入
active - 非法首帧直接进入
closed active下可并发收发多个 request/response- 进入
draining后不再接收新业务请求 draining期间已在途请求仍可完成- 宽限期后强制关闭剩余请求
- 断线后进入
reconnecting - 重连后拿到新
session_id
最终约束
整个 v1 生命周期模型可以压缩成一句话:
- session 建好后进入
active - 要优雅退出就进入
draining - 一旦连接断开或宽限期结束就进入
closed - 若启用自动重连,再从
reconnecting建立新 session
这套模型必须同时适用于:
sdk-agent subprotocolagent-server subprotocol
差异只在握手消息和默认 TLS 策略,不在生命周期语义。
