modify: chongming-request
This commit is contained in:
@@ -13,3 +13,4 @@ data
|
|||||||
logs
|
logs
|
||||||
resources
|
resources
|
||||||
cache_data
|
cache_data
|
||||||
|
output.md
|
||||||
|
|||||||
+1
-1
@@ -49,8 +49,8 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
chongming-worker = { workspace = true }
|
|
||||||
chongming-request = { workspace = true }
|
chongming-request = { workspace = true }
|
||||||
|
chongming-worker = { workspace = true }
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
build = "chongming.scripts.build:build"
|
build = "chongming.scripts.build:build"
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ Example Worker 插件 — 演示 @rpc_method + 显式模型绑定用法
|
|||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import zenoh
|
||||||
|
|
||||||
from chongming_worker import rpc_method, auto_bind_models
|
from chongming_worker import rpc_method, auto_bind_models
|
||||||
from chongming_worker.runtime import create_workers as _create_workers
|
from chongming_worker.runtime import create_workers as _create_workers
|
||||||
|
from chongming_request import Client
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 显式导入 Pydantic 模型(避免 PyArmor 打包后 importlib 动态导入异常)
|
# 显式导入 Pydantic 模型(避免 PyArmor 打包后 importlib 动态导入异常)
|
||||||
@@ -51,7 +54,7 @@ from .models.pydantic import (
|
|||||||
summary="Add two numbers via GET",
|
summary="Add two numbers via GET",
|
||||||
response_model=AddGetResponse,
|
response_model=AddGetResponse,
|
||||||
)
|
)
|
||||||
def add(add_get_request:AddGetRequest) -> AddGetResponse:
|
async def add(add_get_request:AddGetRequest) -> AddGetResponse:
|
||||||
"""加法运算(GET)— 通过查询参数传入 a、b,返回它们的和"""
|
"""加法运算(GET)— 通过查询参数传入 a、b,返回它们的和"""
|
||||||
return AddGetResponse(
|
return AddGetResponse(
|
||||||
result=add_get_request.a + add_get_request.b,
|
result=add_get_request.a + add_get_request.b,
|
||||||
@@ -65,8 +68,19 @@ def add(add_get_request:AddGetRequest) -> AddGetResponse:
|
|||||||
summary="Add two numbers via POST",
|
summary="Add two numbers via POST",
|
||||||
response_model=AddPostResponse,
|
response_model=AddPostResponse,
|
||||||
)
|
)
|
||||||
def add_post(add_post_request: AddPostRequest) -> AddPostResponse:
|
async def add_post(add_post_request: AddPostRequest, session: zenoh.Session) -> AddPostResponse:
|
||||||
"""加法运算(POST)— 通过 JSON Body 传入 a、b,返回它们的和"""
|
"""加法运算(POST)— 通过 JSON Body 传入 a、b,返回它们的和"""
|
||||||
|
async with Client(session=session) as client:
|
||||||
|
add_result = await client.call(
|
||||||
|
worker_type="example",
|
||||||
|
subject="example.add",
|
||||||
|
payload={
|
||||||
|
"a":add_post_request.a,
|
||||||
|
"b":add_post_request.b
|
||||||
|
},
|
||||||
|
method="GET"
|
||||||
|
)
|
||||||
|
print(add_result)
|
||||||
return AddPostResponse(
|
return AddPostResponse(
|
||||||
result=add_post_request.a + add_post_request.b,
|
result=add_post_request.a + add_post_request.b,
|
||||||
operation="add",
|
operation="add",
|
||||||
@@ -80,7 +94,7 @@ def add_post(add_post_request: AddPostRequest) -> AddPostResponse:
|
|||||||
summary="Subtract two numbers",
|
summary="Subtract two numbers",
|
||||||
response_model=SubtractGetResponse,
|
response_model=SubtractGetResponse,
|
||||||
)
|
)
|
||||||
def subtract(subtract_get_request: SubtractGetRequest) -> SubtractGetResponse:
|
async def subtract(subtract_get_request: SubtractGetRequest) -> SubtractGetResponse:
|
||||||
"""减法运算:a - b"""
|
"""减法运算:a - b"""
|
||||||
return SubtractGetResponse(
|
return SubtractGetResponse(
|
||||||
result=subtract_get_request.a - subtract_get_request.b,
|
result=subtract_get_request.a - subtract_get_request.b,
|
||||||
@@ -95,7 +109,7 @@ def subtract(subtract_get_request: SubtractGetRequest) -> SubtractGetResponse:
|
|||||||
summary="Multiply two numbers",
|
summary="Multiply two numbers",
|
||||||
response_model=MultiplyGetResponse,
|
response_model=MultiplyGetResponse,
|
||||||
)
|
)
|
||||||
def multiply(multiply_get_request=MultiplyGetRequest) -> MultiplyGetResponse:
|
async def multiply(multiply_get_request=MultiplyGetRequest) -> MultiplyGetResponse:
|
||||||
"""乘法运算:a * b"""
|
"""乘法运算:a * b"""
|
||||||
return MultiplyGetResponse(
|
return MultiplyGetResponse(
|
||||||
result=multiply_get_request.a * multiply_get_request.b,
|
result=multiply_get_request.a * multiply_get_request.b,
|
||||||
@@ -109,7 +123,7 @@ def multiply(multiply_get_request=MultiplyGetRequest) -> MultiplyGetResponse:
|
|||||||
summary="Divide two numbers",
|
summary="Divide two numbers",
|
||||||
response_model=DivideGetResponse,
|
response_model=DivideGetResponse,
|
||||||
)
|
)
|
||||||
def divide(divide_get_request: DivideGetRequest) -> DivideGetResponse:
|
async def divide(divide_get_request: DivideGetRequest) -> DivideGetResponse:
|
||||||
"""除法运算:a / b(b 不能为 0)"""
|
"""除法运算:a / b(b 不能为 0)"""
|
||||||
if divide_get_request.b == 0:
|
if divide_get_request.b == 0:
|
||||||
return DivideGetResponse(
|
return DivideGetResponse(
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
from .client import Client
|
||||||
@@ -235,59 +235,54 @@ class RPCMethod:
|
|||||||
return raw_result.model_dump()
|
return raw_result.model_dump()
|
||||||
return raw_result
|
return raw_result
|
||||||
|
|
||||||
async def call(self, payload: Dict[str, Any]) -> Any:
|
async def call(self, payload: Dict[str, Any], **extra_kwargs) -> Any:
|
||||||
"""
|
"""
|
||||||
调用原始函数,自动从 payload 提取参数
|
调用原始函数,支持从 payload 和 extra_kwargs 提取参数。
|
||||||
|
|
||||||
流程:
|
|
||||||
1. 校验请求参数(使用绑定的 request_model 或自动生成)
|
|
||||||
2. 提取函数需要的参数
|
|
||||||
3. 调用函数
|
|
||||||
4. 序列化响应(使用绑定的 response_model 或自动生成)
|
|
||||||
|
|
||||||
支持两种函数签名:
|
支持两种函数签名:
|
||||||
- 展开参数: def add(a: float, b: float) -> ... # 传统方式
|
- 展开参数: def add(a: float, b: float) -> ...
|
||||||
- Pydantic 模型: def add(req: AddGetRequest) -> ... # 工程化方式
|
- Pydantic 模型: def add(req: AddGetRequest) -> ...
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
payload: 请求参数字典
|
payload: 请求参数字典
|
||||||
|
**extra_kwargs: 额外关键字参数(如 session, worker_id)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
序列化后的响应数据
|
序列化后的响应数据
|
||||||
"""
|
"""
|
||||||
# 1. 校验请求参数
|
|
||||||
validated_payload = self.validate_request(payload)
|
validated_payload = self.validate_request(payload)
|
||||||
|
|
||||||
# 2. 提取函数需要的参数
|
sig = inspect.signature(self.func)
|
||||||
|
param_names = set(sig.parameters.keys()) - {'self'}
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
|
||||||
|
# 处理模型参数
|
||||||
if self.model_param is not None:
|
if self.model_param is not None:
|
||||||
# 2a. 函数参数是 Pydantic 模型 — 将整个校验后的 payload 转为模型实例传入
|
|
||||||
req_model = self.get_request_model()
|
req_model = self.get_request_model()
|
||||||
if req_model is not None:
|
if req_model is not None:
|
||||||
kwargs[self.model_param] = req_model(**validated_payload)
|
kwargs[self.model_param] = req_model(**validated_payload)
|
||||||
else:
|
else:
|
||||||
# 如果没有 request_model,从函数签名获取模型类型
|
model_type = sig.parameters[self.model_param].annotation
|
||||||
sig = inspect.signature(self.func)
|
|
||||||
hints = get_type_hints(self.func)
|
|
||||||
model_type = hints.get(self.model_param)
|
|
||||||
if isinstance(model_type, type) and issubclass(model_type, BaseModel):
|
if isinstance(model_type, type) and issubclass(model_type, BaseModel):
|
||||||
kwargs[self.model_param] = model_type(**validated_payload)
|
kwargs[self.model_param] = model_type(**validated_payload)
|
||||||
else:
|
else:
|
||||||
kwargs[self.model_param] = validated_payload
|
kwargs[self.model_param] = validated_payload
|
||||||
else:
|
param_names.discard(self.model_param)
|
||||||
# 2b. 传统方式:逐字段提取参数
|
|
||||||
for param_name in self.params:
|
|
||||||
if param_name in validated_payload:
|
|
||||||
kwargs[param_name] = validated_payload[param_name]
|
|
||||||
|
|
||||||
# 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):
|
if inspect.iscoroutinefunction(self.func):
|
||||||
result = await self.func(**kwargs)
|
result = await self.func(**kwargs)
|
||||||
else:
|
else:
|
||||||
result = self.func(**kwargs)
|
result = self.func(**kwargs)
|
||||||
|
|
||||||
# 4. 序列化响应
|
|
||||||
return self.serialize_response(result)
|
return self.serialize_response(result)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,15 +64,13 @@ async def create_worker(
|
|||||||
|
|
||||||
def make_callback(subject: str, methods: List[RPCMethod]):
|
def make_callback(subject: str, methods: List[RPCMethod]):
|
||||||
"""创建处理特定 subject 的回调函数"""
|
"""创建处理特定 subject 的回调函数"""
|
||||||
def callback(query: zenoh.Query):
|
loop = asyncio.get_running_loop()
|
||||||
|
async def _handle_query(query: zenoh.Query):
|
||||||
try:
|
try:
|
||||||
# 解析请求负载
|
# 解析请求负载
|
||||||
# payload_str = str(query.payload) if query.payload else "{}"
|
# payload_str = str(query.payload) if query.payload else "{}"
|
||||||
payload_bytes = bytes(query.payload) if query.payload else b""
|
payload_bytes = bytes(query.payload) if query.payload else b""
|
||||||
if not payload_bytes:
|
data = orjson.loads(payload_bytes) if payload_bytes else {}
|
||||||
data = {}
|
|
||||||
else:
|
|
||||||
data = orjson.loads(payload_bytes)
|
|
||||||
http_method = data.get("_method", "GET").upper()
|
http_method = data.get("_method", "GET").upper()
|
||||||
|
|
||||||
# 匹配方法(按 HTTP 方法)
|
# 匹配方法(按 HTTP 方法)
|
||||||
@@ -87,7 +85,11 @@ async def create_worker(
|
|||||||
return
|
return
|
||||||
|
|
||||||
# 调用 RPC 方法(支持同步和异步)
|
# 调用 RPC 方法(支持同步和异步)
|
||||||
result = asyncio.run(matched.call(data))
|
result = await matched.call(
|
||||||
|
data,
|
||||||
|
session=session,
|
||||||
|
worker_id=worker_id
|
||||||
|
)
|
||||||
|
|
||||||
# 回复
|
# 回复
|
||||||
query.reply(
|
query.reply(
|
||||||
@@ -107,6 +109,11 @@ async def create_worker(
|
|||||||
payload=json.dumps(error_response).encode("utf-8")
|
payload=json.dumps(error_response).encode("utf-8")
|
||||||
)
|
)
|
||||||
print(f"[Worker] {worker_id} 异常 {subject}: {e}")
|
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
|
return callback
|
||||||
|
|
||||||
# 声明所有 Queryable
|
# 声明所有 Queryable
|
||||||
@@ -119,6 +126,7 @@ async def create_worker(
|
|||||||
print(f"[Worker] {worker_id} Queryable: '{key}' [{', '.join(m.method for m in methods)}]")
|
print(f"[Worker] {worker_id} Queryable: '{key}' [{', '.join(m.method for m in methods)}]")
|
||||||
|
|
||||||
# 6. 保持 worker 存活直到被取消
|
# 6. 保持 worker 存活直到被取消
|
||||||
|
stop_event = asyncio.Event()
|
||||||
try:
|
try:
|
||||||
await stop_event.wait()
|
await stop_event.wait()
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
|
|||||||
Reference in New Issue
Block a user