Skip to content

Python — Server API

Server 文档按使用路径组织:接受 session、接收提交、发送结果或 drop、关闭。低层消息和 packet 细节保留在对应参考页。

导入

python
from nnrp.server import (
    ServerProfile,
    ServerSession,
    ServerSessionAcceptResolution,
    ReceivedSubmit,
    accept_server_connection,
    accept_server_session,
)

Server 使用流程

  1. 构造 ServerProfile
  2. serve_tcpserve_quic 打开 listener。
  3. 对每个 listener 调用 accept_server_session,或在已经预读首包、已经接受 connection 的 runtime 中调用 accept_server_connection
  4. 循环调用 ServerSession.receive_submit
  5. send_resultsend_result_drop 回答每一帧。
  6. 对端断开或应用拒绝继续处理时关闭 session。

NativeRuntimeServerSession Preview4 Frame

Native server host 与 client 使用同一个角色中立 runtime-frame ABI。Server session 提供 以下应用接口:

方法消息
send_progress(metadata, body=b"")PROGRESS
send_partial_result(metadata, body=b"")PARTIAL_RESULT
send_backpressure(metadata), send_credit_update(metadata)pressure 消息
send_result_drop_reason(metadata, diagnostic=b"")RESULT_DROP_REASON
send_trace_context(metadata, body=b"")TRACE_CONTEXT
send_recoverable_error(metadata, diagnostic=b""), send_retry_after(...)recovery 消息
declare_object, reference_object, release_objectobject lifecycle 消息
patch_object, send_object_deltaobject update 消息
reference_cache, report_cache_miss, invalidate_cachecache 消息

poll_runtime_frames()iter_runtime_frames() 返回已经解码的 NativeRuntimeFrameEvent。应用侧 server 方法不接收原始 control_code

accept_server_session

接受连接、校验 CLIENT_HELLO、发送 SERVER_HELLO_ACK,并返回活跃 ServerSession

参数类型必填取值 / 范围说明
listenerServerListener已打开 listenerQUIC/TCP listener。
session_idint | None默认客户端请求值服务端分配或覆盖的 session id。
active_model_namestr默认 ""SDK 保留在 ServerSession.active_model_name,不写入 SERVER_HELLO_ACK body。
server_profileServerProfile默认 ServerProfile()服务端 capability 和限制。
timeoutfloat秒,默认 10.0accept 与握手读取超时。
session_resolverCallable[[ClientHelloContext], ServerSessionAcceptResolution | Awaitable[...]] | None默认 None在解析 CLIENT_HELLO 后决定实际 session_idactive_model_name
返回可能抛出
ServerSessiontransport、认证、握手解析、capability 拒绝错误。
python
session = await accept_server_session(
    listener,
    server_profile=ServerProfile(max_concurrent_frames=4),
    active_model_name="render-v1",
)

accept_server_connection

对已经接受的 transport connection 执行服务端握手。这个入口用于 runtime 已经拿到 connection,或者为了 TRANSPORT_PROBE / 自定义探测流程已经预读了首个 control packet 的场景。

参数类型必填取值 / 范围说明
connectionServerConnection已接受连接QUIC/TCP connection。
first_packetNnrpPacket | None默认 None已预读的 CLIENT_HELLO;为空时 SDK 自行读取。
session_idint | None默认客户端请求值未提供 session_resolver 时使用。
active_model_namestr默认 ""返回在 ServerSession 上供应用观察。
server_profileServerProfile默认 ServerProfile()服务端 capability 和限制。
timeoutfloat秒,默认 10.0读取握手包超时。
session_resolverCallable[[ClientHelloContext], ServerSessionAcceptResolution | Awaitable[...]] | None默认 None根据已解析 CLIENT_HELLO 决定服务端 session。

accept_server_connectionaccept_server_session 都由 SDK 统一构造 SERVER_HELLO_ACK。 Preview3 SDK 会在 ACK body 中写入 control_extension_block,至少包含 transport policy ack 扩展,用来声明 active_transport_idcontrol_extension_bytes 必须等于 ACK body 长度; 应用层模型名、业务 session id 映射等信息不得塞进 ACK body。

python
def resolve_session(hello):
    requested_model = hello.auth_block.decode("utf-8") if hello.auth_block else ""
    opened = open_runtime_session(requested_model)
    return ServerSessionAcceptResolution(
        session_id=opened.wire_session_id,
        active_model_name=opened.active_model_name,
    )

session = await accept_server_connection(
    connection,
    first_packet=client_hello_packet,
    server_profile=ServerProfile(max_concurrent_frames=4),
    session_resolver=resolve_session,
)

ServerSession.receive_submit

接收并解析下一条 FRAME_SUBMIT

参数类型必填取值 / 范围说明
timeoutfloat | None秒;None 表示不超时等待提交的最长时间。
返回可能抛出
ReceivedSubmit超时、包格式错误、session mismatch、wire format 不支持。
python
received = await session.receive_submit(timeout=30.0)

ServerSession.send_result

推送一帧推理结果。

参数类型必填取值 / 范围说明
frame_idint来自 ReceivedSubmit用于关联请求。
tile_idstuple[int, ...]默认空结果 tile id。
sectionstuple[TensorSectionData, ...]默认空Tensor 结果 sections。
typed_payloadstuple[TypedPayload, ...]默认空非 tensor payload。
result_classResultClass默认 COMPLETE结果完整性。
applied_budget_policyBudgetPolicy默认 NONE服务端实际使用的降级策略。
inference_msint毫秒推理耗时。
queue_msint毫秒排队耗时。
server_total_msint毫秒服务端总耗时。
status_codeint应用自定义状态细节。
返回可能抛出
int 发送字节数序列化或 transport 错误。
python
await session.send_result(
    frame_id=received.metadata.frame_id,
    sections=run_inference(received.request),
    result_class=ResultClass.COMPLETE,
)

ServerSession.send_result_drop

通知客户端某一帧不会返回结果。

参数类型必填取值 / 范围说明
frame_idint已提交 frame id要 drop 的帧。
reasonint应用自定义当前消息形态支持时使用。
返回可能抛出
int 发送字节数序列化或 transport 错误。
python
await session.send_result_drop(frame_id=received.metadata.frame_id)

核心类型

ServerProfile

字段类型默认值说明
max_concurrent_framesint1协议层 in-flight 限制。
enable_cacheboolTrue是否启用 cache 协商。
max_sectionsint16每帧最大 tensor section 数。
max_body_bytesint33554432最大请求 body 字节数。

ReceivedSubmit

字段类型说明
packetNnrpPacket原始 FRAME_SUBMIT 包。
metadataFrameSubmitMetadata解析后的 frame metadata。
requestSubmitRequest结构化提交请求。
tensor_bodyTensorBodyView | None存在 tensor payload 时的 body view。

ClientHelloContext

服务端握手解析结果,保存在 ServerSession.hello,也会传给 session_resolver

字段类型说明
packetNnrpPacket原始 CLIENT_HELLO
metadataClientHelloMetadata解析后的握手 metadata。
auth_blockbytes应用定义的认证或模型请求载荷。
control_extensionstuple[ControlExtensionEntry, ...]已解析握手扩展。

ServerSessionAcceptResolution

session_resolver 的返回值。

字段类型说明
session_idint服务端最终接受的 wire session id。
active_model_namestr应用可观测的活动模型名,不进入 ACK body。

示例

python
async def handle_session(session: ServerSession) -> None:
    try:
        while True:
            received = await session.receive_submit(timeout=30.0)
            sections = await run_inference_async(received.request)
            await session.send_result(
                frame_id=received.metadata.frame_id,
                sections=sections,
                result_class=ResultClass.COMPLETE,
            )
    finally:
        await session.close()

常见坑

WARNING

  1. 不要在 receive coroutine 里直接跑阻塞推理;用 executor 或 worker pool。
  2. 每个已接受 frame 都需要 result 或 drop。
  3. max_concurrent_frames 是协议限制,不是完整调度器。
  4. Runtime 不要手工构造 SERVER_HELLO_ACK;需要预读首包时使用 accept_server_connection(first_packet=...)

NNRP Documentation