WechatOnCloud/bridge/woc_bridge/routes/batch.py

107 lines
3.1 KiB
Python
Raw Normal View History

"""群发消息路由。
端点
- POST /api/send/batch 提交群发任务
- GET /api/send/batch 列出最近 N 条群发任务
- GET /api/send/batch/{batch_id}/status 查询群发进度
- POST /api/send/batch/{batch_id}/cancel 取消群发
"""
from __future__ import annotations
import logging
from fastapi import APIRouter, Request
from woc_bridge.config import _require_batch_worker
from woc_bridge.models import BridgeError, BatchSendRequest
logger = logging.getLogger("woc-bridge")
router = APIRouter(prefix="/api/send/batch", tags=["batch-send"])
@router.post("")
async def submit_batch(req: BatchSendRequest, request: Request):
"""提交群发任务。
请求体BatchSendRequesttargets / content / client_request_id / abort_on_consecutive_fail
返回{"success": True, "batch_id": str, "status": str, "status_query_url": str}
异常
- 400 INVALID_PARAMStargets 超过单批上限
- 409 INVALID_PARAMSbatch_id 重复批级幂等命中
- 429 RATE_LIMITED日频次超限 / 批间隔不足
"""
worker = _require_batch_worker()
batch_id = await worker.submit_batch(req)
status = await worker.get_status(batch_id)
return {
"success": True,
"batch_id": batch_id,
"status": status.status if status is not None else "pending",
"status_query_url": f"/api/send/batch/{batch_id}/status",
}
@router.get("/{batch_id}/status")
async def get_batch_status(batch_id: str):
"""查询群发进度。
返回 BatchSendStatus total / processed / success / failed / skipped /
progress / estimated_remaining_sec / items 等字段
异常
- 404 NOT_FOUNDbatch_id 不存在
"""
worker = _require_batch_worker()
status = await worker.get_status(batch_id)
if status is None:
raise BridgeError(
code="NOT_FOUND",
message=f"batch_id={batch_id} 不存在",
http_status=404,
)
return status
@router.post("/{batch_id}/cancel")
async def cancel_batch(batch_id: str):
"""取消群发。
已处理条目保留结果未处理条目标记 skipped
异常
- 404 NOT_FOUNDbatch_id 不存在或已完成
"""
worker = _require_batch_worker()
cancelled = await worker.cancel_batch(batch_id)
if not cancelled:
raise BridgeError(
code="NOT_FOUND",
message=f"batch_id={batch_id} 不存在或已完成",
http_status=404,
)
return {"success": True, "batch_id": batch_id, "status": "cancelled"}
@router.get("")
async def list_batches(limit: int = 20):
"""列出最近 N 条群发任务(按提交时间倒序)。
Query 参数
- limit返回条数1-100默认 20
异常
- 400 INVALID_PARAMSlimit 越界
"""
worker = _require_batch_worker()
if limit < 1 or limit > 100:
raise BridgeError(
code="INVALID_PARAMS",
message="limit 必须在 1-100 之间",
http_status=400,
)
batches = await worker.list_batches(limit)
return {"batches": batches}