modify: chongming-request

This commit is contained in:
2026-07-17 12:08:08 +08:00
parent bf2d6ea7c4
commit 247005bc79
6 changed files with 56 additions and 37 deletions
@@ -0,0 +1 @@
from .client import Client
+19 -24
View File
@@ -235,59 +235,54 @@ class RPCMethod:
return raw_result.model_dump()
return raw_result
async def call(self, payload: Dict[str, Any]) -> Any:
async def call(self, payload: Dict[str, Any], **extra_kwargs) -> Any:
"""
调用原始函数,自动从 payload 提取参数
流程:
1. 校验请求参数(使用绑定的 request_model 或自动生成)
2. 提取函数需要的参数
3. 调用函数
4. 序列化响应(使用绑定的 response_model 或自动生成)
调用原始函数,支持从 payload 和 extra_kwargs 提取参数。
支持两种函数签名:
- 展开参数: def add(a: float, b: float) -> ... # 传统方式
- Pydantic 模型: def add(req: AddGetRequest) -> ... # 工程化方式
- 展开参数: def add(a: float, b: float) -> ...
- Pydantic 模型: def add(req: AddGetRequest) -> ...
Args:
payload: 请求参数字典
**extra_kwargs: 额外关键字参数(如 session, worker_id)
Returns:
序列化后的响应数据
"""
# 1. 校验请求参数
validated_payload = self.validate_request(payload)
# 2. 提取函数需要的参数
sig = inspect.signature(self.func)
param_names = set(sig.parameters.keys()) - {'self'}
kwargs = {}
# 处理模型参数
if self.model_param is not None:
# 2a. 函数参数是 Pydantic 模型 — 将整个校验后的 payload 转为模型实例传入
req_model = self.get_request_model()
if req_model is not None:
kwargs[self.model_param] = req_model(**validated_payload)
else:
# 如果没有 request_model,从函数签名获取模型类型
sig = inspect.signature(self.func)
hints = get_type_hints(self.func)
model_type = hints.get(self.model_param)
model_type = sig.parameters[self.model_param].annotation
if isinstance(model_type, type) and issubclass(model_type, BaseModel):
kwargs[self.model_param] = model_type(**validated_payload)
else:
kwargs[self.model_param] = validated_payload
else:
# 2b. 传统方式:逐字段提取参数
for param_name in self.params:
if param_name in validated_payload:
kwargs[param_name] = validated_payload[param_name]
param_names.discard(self.model_param)
# 3. 调用函数
# 普通参数:优先 validated_payload,其次 extra_kwargs
for name in param_names:
if name in validated_payload:
kwargs[name] = validated_payload[name]
elif name in extra_kwargs:
kwargs[name] = extra_kwargs[name]
# 否则函数使用默认值(如果有)
# 调用函数
if inspect.iscoroutinefunction(self.func):
result = await self.func(**kwargs)
else:
result = self.func(**kwargs)
# 4. 序列化响应
return self.serialize_response(result)
+14 -6
View File
@@ -64,15 +64,13 @@ async def create_worker(
def make_callback(subject: str, methods: List[RPCMethod]):
"""创建处理特定 subject 的回调函数"""
def callback(query: zenoh.Query):
loop = asyncio.get_running_loop()
async def _handle_query(query: zenoh.Query):
try:
# 解析请求负载
# payload_str = str(query.payload) if query.payload else "{}"
payload_bytes = bytes(query.payload) if query.payload else b""
if not payload_bytes:
data = {}
else:
data = orjson.loads(payload_bytes)
data = orjson.loads(payload_bytes) if payload_bytes else {}
http_method = data.get("_method", "GET").upper()
# 匹配方法(按 HTTP 方法)
@@ -87,7 +85,11 @@ async def create_worker(
return
# 调用 RPC 方法(支持同步和异步)
result = asyncio.run(matched.call(data))
result = await matched.call(
data,
session=session,
worker_id=worker_id
)
# 回复
query.reply(
@@ -107,6 +109,11 @@ async def create_worker(
payload=json.dumps(error_response).encode("utf-8")
)
print(f"[Worker] {worker_id} 异常 {subject}: {e}")
def callback(query: zenoh.Query):
# 当前 create_worker 运行在事件循环中,可直接 create_task
asyncio.run_coroutine_threadsafe(_handle_query(query), loop)
return callback
# 声明所有 Queryable
@@ -119,6 +126,7 @@ async def create_worker(
print(f"[Worker] {worker_id} Queryable: '{key}' [{', '.join(m.method for m in methods)}]")
# 6. 保持 worker 存活直到被取消
stop_event = asyncio.Event()
try:
await stop_event.wait()
except asyncio.CancelledError: