Function Runtime Server 协议
Function Runtime Server 协议
状态:已接受;已实现
本文定义 function-mode Run 的内部 gRPC 协议。它细化了 Function Mode 生命周期与 Invoke Dataplane ,但不改变公开 Run API,也不会把 Runtime Server 暴露到 Runtime Pod 外。
范围
基础 Runtime service 支持一次性执行。支持 function mode 的 Runtime Server 会额外注册可选的
FunctionRuntime service,它提供四个只由 runtimed 在 Pod 内调用的操作:
RegisterFunction创建或恢复一个可调用 function 注册;FunctionStatus查询本地就绪、活动和致命状态;InvokeFunction执行一次有界 invocation;UnregisterFunctiondrain 或取消工作,并删除本地状态。
Runtime Server 不读取 Kubernetes 对象、不认证调用方、不路由 gateway 请求、不上传 artifact,也不调度 capacity。这些职责分别属于 runtimed、Runtime gateway 和 control plane。invocation artifact 不属于 v0.x 范围。
runtimed 也会在 Runtime Service port 为 gateway traffic 实现同一个 FunctionRuntime service。
仅在该 proxy hop,InvokeFunctionRequest.registration 提供 run_uid,而 registration_id 为空。
runtimed 解析当前 assigned owner 及其私有 active registration,填入 opaque ID 后调用 colocated
Runtime Server。Runtime Server 本身始终要求非空 registration ID;gateway 不会看到或提供它。
function 支持对 custom Runtime 是 opt-in:只支持一次性执行的 Runtime 只需实现并注册 Runtime。
以下精确 message shape 和语义必须在修改 runtime.proto、生成 stubs 或内置 Runtime 实现前完成评审。
注册标识
对于一次性 Run,Run.status.attempt 统计 execution attempts。对于 function Run,它统计
registration lifecycle attempts:初始 registration 为 1,只有在 registration failure 进入 retry
或 reassignment 时,shared retry engine 才递增它。对同一 registration attempt 的不确定 Pod-local
RegisterFunction RPC 进行重试是幂等的,且不改变 Run status。
registration_attempt 不是 invocation counter。每一次 function 调用可选地携带独立的
invocation_id 用于关联。
RegisterFunction 使用 Run UID 加 registration_attempt 建立新的本地 registration generation,
并返回 opaque registration_id。后续所有 Pod-local 操作使用这个 ID,而不再重复传递 attempt。
Runtime Server 将该 ID 绑定到 Run UID 和 registration attempt;stale ID 绝不能修改、invoke 或删除
新的 registration。
registration_digest 是 runtimed 对规范化且不可变的注册输入计算得到的小写 SHA-256:已
解析的 source identity、handler、environment 和 Runtime 可见的注册设置。它不包含短暂的
working-directory 路径;它是幂等校验,不是凭据。
调用与 Registration Fence 示例
以下展示 runtimed 发往 Pod-local Runtime Server 的调用。它是建议协议的示例,不是公开 gateway 命令。
UID 为
2b5d...的 function Run 在 Runtime Pod A 上开始第一次 registration。此时Run.status.attempt为1,runtimed A 注册该 function:grpcurl -plaintext -d '{ "runUid": "2b5d...", "registrationAttempt": 1, "workingDir": "/workspace/runs/2b5d", "handler": "handler.handle", "idleTimeoutSeconds": 300, "registrationDigest": "sha256:..." }' 127.0.0.1:9090 executor.v1.FunctionRuntime/RegisterFunction成功 response 包含 Runtime Server 生成的 registration reference:
{ "registration": { "runUid": "2b5d...", "registrationId": "reg_01J..." }, "state": "FUNCTION_REGISTRATION_STATE_READY" }gateway 将请求路由到 runtimed A。它分配 invocation ID,并发送 payload,不创建新的 Kubernetes object:
grpcurl -plaintext -d '{ "registration": { "runUid": "2b5d...", "registrationId": "reg_01J..." }, "invocationId": "01J...", "contentType": "application/json", "input": "eyJjb21tYW5kIjoic3RhdHVzIn0=" }' 127.0.0.1:9090 executor.v1.FunctionRuntime/InvokeFunction在 protobuf JSON 中,
bytes使用 base64 编码;解码后的 input 为{"command":"status"}。另一调用会使用新的invocation_id,但只要同一 registration 仍在 活动,使用同一个 registration ID。如果 registration failure 发生且 retry policy 允许 recovery,shared retry engine 会在 scheduler 分配或重新分配 Runtime Pod 前将
Run.status.attempt推进到2。下一次RegisterFunction使用registration_attempt: 2,并获得新的 registration ID。携带reg_01J...的 invoke 或 unregister 在新 registration 取代它后必须返回FailedPrecondition;它不能影响新 registration。
gateway 和 runtimed 还会使用 assigned Pod identity 对 routing 做 fence。registration ID 保护的是 Runtime Server 的本地 registration state;它不保证 invocation exactly once。
建议的 Protobuf API
基础 executor.v1.Runtime service 保持一次性执行语义。支持 function 的 Runtime Server 会在同一
gRPC server 上额外注册以下可选 service:
service FunctionRuntime {
// 创建或恢复一个本地 function registration。
rpc RegisterFunction(RegisterFunctionRequest) returns (RegisterFunctionResponse);
// 返回本地就绪、活动和致命状态。
rpc FunctionStatus(FunctionStatusRequest) returns (FunctionStatusResponse);
// 执行一次有界 function invocation。
rpc InvokeFunction(InvokeFunctionRequest) returns (InvokeFunctionResponse);
// Drain 或取消工作,并删除本地状态。
rpc UnregisterFunction(UnregisterFunctionRequest) returns (UnregisterFunctionResponse);
}
message FunctionRegistration {
// Kubernetes Run UID,不使用可变的 name。
string run_uid = 1;
// Runtime Server 为一个本地 registration generation 生成的 opaque ID。
string registration_id = 2;
}
message RegisterFunctionRequest {
string run_uid = 1;
int32 registration_attempt = 2;
string working_dir = 3;
string handler = 4;
map<string, string> env = 5;
int64 idle_timeout_seconds = 6;
string registration_digest = 7;
}
message RegisterFunctionResponse {
FunctionRegistration registration = 1;
FunctionRegistrationState state = 2;
}
message FunctionStatusRequest { FunctionRegistration registration = 1; }
message FunctionStatusResponse {
FunctionRegistration registration = 1;
FunctionRegistrationState state = 2;
int32 in_flight = 3;
int64 last_activity_unix_nano = 4;
string fatal_error = 5;
}
message InvokeFunctionRequest {
FunctionRegistration registration = 1;
string invocation_id = 2;
bytes input = 3;
string content_type = 4;
int64 timeout_millis = 5;
}
message InvokeFunctionResponse {
FunctionRegistration registration = 1;
string invocation_id = 2;
bytes output = 3;
string content_type = 4;
map<string, string> outputs = 5;
}
message UnregisterFunctionRequest {
FunctionRegistration registration = 1;
bool cancel_in_flight = 2;
int64 drain_timeout_millis = 3;
}
message UnregisterFunctionResponse { FunctionRegistration registration = 1; }
enum FunctionRegistrationState {
FUNCTION_REGISTRATION_STATE_UNSPECIFIED = 0;
FUNCTION_REGISTRATION_STATE_REGISTERING = 1;
FUNCTION_REGISTRATION_STATE_READY = 2;
FUNCTION_REGISTRATION_STATE_DRAINING = 3;
FUNCTION_REGISTRATION_STATE_FAILED = 4;
}
gateway 初期接收 JSON,并设置 content_type=application/json。本地协议使用 opaque bytes,
使受信 custom Runtime 后续可采用其他编码。输入和 response bytes 不写入 Run.status。
注册与状态语义
RegisterFunction 在接收工作前校验 working directory、handler、environment、timeout、digest 和
从一开始计数的 registration_attempt。
- 重复相同 Run UID、registration attempt 和 digest 时返回当前 registration reference,不重新 初始化 function。
- 同一 Run UID 和 registration attempt 使用不同 digest 时返回
AlreadyExists,不替换注册。 - 更高 registration attempt 会取代旧本地 registration,并创建新的 opaque registration ID;更低
attempt 返回
FailedPrecondition。 - 永久初始化失败通过
FunctionStatus的FAILED和有界fatal_error暴露。
FunctionStatus 只读取 Runtime Server 本地状态。last_activity_unix_nano 在 registration
变为 ready 时初始化,并在 invocation 开始或完成时更新。这样从未 invoke 的 registration 也会受其
idle timeout 约束。fatal_error 是有界诊断文本而不是日志。NotFound 表示没有该 Run UID 的
registration;FailedPrecondition 表示 registration ID 已过期、正在 drain 或未就绪。runtimed
以有界频率轮询它用于健康检查和 idle timeout,绝不把每次 activity 更新写回 Kubernetes。
如果被分配的 Runtime Pod 没有注册 FunctionRuntime,runtimed 会收到 Unimplemented。这是永久
配置失败:Run 不能回退到一次性执行,而是依照不兼容 Runtime 的正常 terminal 或 retry policy 处理。
Invocation 语义
InvokeFunction 要求提供的 registration reference 处于 READY。v0.x 每个 function Run 只允许一个
in-flight invocation,并且不排队。
invocation_id是可选的关联数据,最大 128 bytes。调用方可提供它用于跨系统 trace;为空时 Runtime Server 生成 opaque ID,response 始终返回实际使用的 ID。- 它不是去重 key。未知结果后的重试可能再次执行;dispatch 后没有组件自动重试。
timeout_millis由 runtimed 限制为剩余 Run 生命周期和 gateway deadline 以内。零表示 有界 gateway 默认值,绝不代表无限运行。ResourceExhausted映射为 gateway HTTP 429。DeadlineExceeded仅影响本次 invocation, 不影响 function Run 生命周期。draining、stale 或未就绪注册的FailedPrecondition映射为 HTTP 503。
outputs 使用与 Run.status.outputs 相同的 key、数量和 value 限制,但它们只从本次
invocation 返回,绝不追加到 Run.status。每个内置 Runtime 都会获得一个 invocation-local
KRUNTIME_OUTPUTS 路径,并可写入已有的 KEY=VALUE 格式。runtimed 会在唯一允许的
in-flight invocation 前清空该文件,在成功响应后解析,并将有界值填入本 RPC response。
Runtime 可以增加已文档化且兼容的 output source。内置 Python adapter 识别 handler return object
顶层的 outputs field:它必须是 map[string]string;原始 object 仍完整地作为 output 返回,
该 field 的值作为 response outputs。file 与 Python-return outputs 仅在 key 完全不重复时才合并;
duplicate key、invalid value 或超过限制都会使本次 invocation 失败,而不会静默覆盖数据。v0.x 的
function invocation 不生成 artifact declaration 或 ArtifactRef。未来需要先定义 lifecycle、
retention 和 storage boundary,才能扩展这个 local protocol。
owner runtimed 对每个 invocation 输出一条有界 JSONL audit record,以 Run UID 和 invocation ID
为 key,并包含 operation、outcome、gRPC status code 和 duration。它绝不记录 request body、response
body 或 output value。adapter 捕获的 function output 写入 RPC 的 output field,而不会自动记录为
日志;两种 output 都不写入 Run.status.message。
注销
UnregisterFunction 先转为 DRAINING 并拒绝新 invocation。cancel_in_flight=false 时,
最多等待 drain_timeout_millis 直到活动 invocation 完成;cancel_in_flight=true 时,立即
取消后释放 registration-local state。
注销不存在的 registration 应成功。注销 stale registration ID 必须返回
FailedPrecondition,且不能删除同一 Run UID 的新 registration。
限制与错误映射
| 值 | 初始限制 | 强制方 |
|---|---|---|
| Request body | 1 MiB | Gateway 与 runtimed |
| Registration ID | 128 bytes | Runtime Server 与 runtimed |
| Invocation ID | 128 bytes | Gateway 与 runtimed |
| Response body | 1 MiB | runtimed |
| Outputs | 现有 Run output 限制 | runtimed |
| In-flight calls | 每个 function Run 一个 | Runtime Server |
fatal_error | 4 KiB | Runtime Server |
| gRPC code | 含义 | Gateway 结果 |
|---|---|---|
InvalidArgument | 无效 handler、path、payload 或 limit | HTTP 400 |
NotFound | 未知注册 | HTTP 404,或 cache recheck 后 HTTP 503 |
AlreadyExists | 相同 registration attempt、不同 digest | Registration failure |
FailedPrecondition | Stale registration ID 或未就绪 registration | HTTP 503 |
ResourceExhausted | Invocation 已在执行 | HTTP 429 |
DeadlineExceeded | Invocation deadline 已到 | HTTP 504 |
Unavailable | Runtime Server 无法接收工作 | HTTP 503 与 lifecycle recovery |
内置 Runtime 要求
Python 导入 module.function,传递解码后的 JSON input,并把返回值编码为 JSON output。Bash 遵循
AWS Lambda custom runtime 的 handler 模型
:
handler 为 file.function,其中 file 是相对于已注册
working directory 的 .sh 文件名。注册时 Bash Runtime source file.sh,并校验 function 存在。
处理 application/json invocation 时,它以单个、已引用的位置参数传入 payload,并捕获 handler
stdout 作为 response output。它绝不把 handler 或 request payload 当作 shell source 执行,也不把
request data 插值进 command string。两个 adapter 都只能在已注册的 working directory 下运行,遵守
context cancellation,并且每个 registration 最多一个活动 invocation。
现有只支持一次性执行的 Runtime Server 仍然有效。只有未来的兼容性/健康握手确认这些 RPC 受支持后才启用
function mode;不得通过 Execute 模拟 function invocation。
待确认的评审决策
- 在 function mode 中使用
Run.status.attempt表示 registration lifecycle attempt;后续本地 调用使用 Runtime Server 生成的 registration ID,并以它 fence stale operation。 - 本地 invoke payload 使用 opaque bytes 加 content type;JSON 是第一个 gateway 编码。
- invocation artifact 不属于 v0.x 范围。
- 不承诺 invocation-ID 去重,也不承诺自动 execution retry。
- v0.x 每个已注册 function Run 最多一个 in-flight invocation。
批准后,实现可以拆为 protobuf/stub generation、Bash/Python adapters,以及 runtimed registration lifecycle/gateway 工作。