|
|
@@ -39,14 +39,18 @@ except Exception: # pragma: no cover
|
|
|
class DemandStartRequest(BaseModel):
|
|
|
cluster_name: str
|
|
|
platform_type: Literal["piaoquan", "changwen"]
|
|
|
+ count: int
|
|
|
|
|
|
|
|
|
-# 定时任务配置:请按需修改/补齐
|
|
|
-# 说明:平台映射关系由 platform_type 决定;cluster_name 将用于匹配 demand_task.name
|
|
|
-DEMAND_SCHEDULE_CLUSTER_PLATFORM_LIST: list[dict] = [{
|
|
|
- "cluster_name":"贪污腐败",
|
|
|
- "platform_type":"piaoquan",
|
|
|
-}]
|
|
|
+def _get_demand_schedule_cluster_platform_list() -> list[dict]:
|
|
|
+ """动态获取定时任务列表。"""
|
|
|
+ try:
|
|
|
+ # 延迟导入:避免服务启动时因 ODPS 依赖缺失直接失败
|
|
|
+ from examples.demand.data_query_tools import get_demand_merge_level2_names
|
|
|
+ return get_demand_merge_level2_names() or []
|
|
|
+ except Exception as e: # pragma: no cover
|
|
|
+ print(f"获取定时任务列表失败: {e}")
|
|
|
+ return []
|
|
|
|
|
|
# 是否开启定时任务(可选,通过环境变量覆盖)
|
|
|
DEMAND_SCHEDULER_ENABLED: bool = os.getenv("DEMAND_SCHEDULER_ENABLED", "1").strip() == "1"
|
|
|
@@ -64,39 +68,50 @@ def _get_today_time_window(now: datetime) -> tuple[datetime, datetime]:
|
|
|
return start_of_today, end_of_today
|
|
|
|
|
|
|
|
|
-async def demand_start_sync(cluster_name: str, platform_type: Literal["piaoquan", "changwen"]) -> dict:
|
|
|
+async def demand_start_sync(cluster_name: str, platform_type: Literal["piaoquan", "changwen"], count) -> dict:
|
|
|
"""
|
|
|
与 /demand/start 同一执行链路,但不创建后台任务:prepare -> create demand_task -> 串行 await run_demand。
|
|
|
"""
|
|
|
# prepare 阶段是同步的(当前示例代码为 sync),这里保持同步串行语义
|
|
|
execution_id = None
|
|
|
- if platform_type == "piaoquan":
|
|
|
- execution_id = piaoquan_prepare(cluster_name)
|
|
|
- elif platform_type == "changwen":
|
|
|
- execution_id = changwen_prepare(cluster_name)
|
|
|
- elif platform_type == "zengzhang":
|
|
|
- execution_id = zengzhang_prepare(cluster_name)
|
|
|
-
|
|
|
- if not execution_id:
|
|
|
- raise HTTPException(status_code=400, detail="获取 execution_id 失败")
|
|
|
-
|
|
|
- task_name = cluster_name[:32] if cluster_name else None
|
|
|
- task_id = _create_demand_task(
|
|
|
- execution_id=execution_id,
|
|
|
- name=task_name,
|
|
|
- platform=platform_type,
|
|
|
- )
|
|
|
- if not task_id:
|
|
|
- raise HTTPException(status_code=500, detail="创建 demand_task 失败")
|
|
|
-
|
|
|
- # run_once 内部 finally 会把 task 状态写回 MySQL
|
|
|
- result = await run_demand(
|
|
|
- cluster_name,
|
|
|
- platform_type,
|
|
|
- execution_id=execution_id,
|
|
|
- task_id=task_id,
|
|
|
- )
|
|
|
- return {"ok": True, "message": "调用成功", "task_id": task_id, "execution_id": execution_id, "result": result}
|
|
|
+ task_id: Optional[int] = None
|
|
|
+ try:
|
|
|
+ if platform_type == "piaoquan":
|
|
|
+ execution_id = piaoquan_prepare(cluster_name)
|
|
|
+ elif platform_type == "changwen":
|
|
|
+ execution_id = changwen_prepare(cluster_name)
|
|
|
+ elif platform_type == "zengzhang":
|
|
|
+ execution_id = zengzhang_prepare(cluster_name)
|
|
|
+
|
|
|
+ if not execution_id:
|
|
|
+ raise ValueError("获取 execution_id 失败")
|
|
|
+
|
|
|
+ task_name = cluster_name[:32] if cluster_name else None
|
|
|
+ task_id = _create_demand_task(
|
|
|
+ execution_id=execution_id,
|
|
|
+ name=task_name,
|
|
|
+ platform=platform_type,
|
|
|
+ )
|
|
|
+ if not task_id:
|
|
|
+ raise ValueError("创建 demand_task 失败")
|
|
|
+
|
|
|
+ # run_once 内部 finally 会把 task 状态写回 MySQL
|
|
|
+ result = await run_demand(
|
|
|
+ cluster_name,
|
|
|
+ platform_type,
|
|
|
+ count,
|
|
|
+ execution_id=execution_id,
|
|
|
+ task_id=task_id,
|
|
|
+ )
|
|
|
+ return {"ok": True, "message": "调用成功", "task_id": task_id, "execution_id": execution_id, "result": result}
|
|
|
+ except Exception as e:
|
|
|
+ return {
|
|
|
+ "ok": False,
|
|
|
+ "message": f"执行失败: {e}",
|
|
|
+ "task_id": task_id,
|
|
|
+ "execution_id": execution_id,
|
|
|
+ "result": None,
|
|
|
+ }
|
|
|
|
|
|
|
|
|
def _today_has_status_0_or_1(cluster_name: str, platform_type: str, now: datetime) -> bool:
|
|
|
@@ -134,13 +149,16 @@ async def demand_scheduled_run_once() -> None:
|
|
|
遍历配置列表 -> 查当天 demand_task -> 匹配 cluster_name/name & platform_type/platform
|
|
|
若存在 status=0 或 1 的记录则跳过;否则执行一次 demand_start_sync。
|
|
|
"""
|
|
|
- if not DEMAND_SCHEDULE_CLUSTER_PLATFORM_LIST:
|
|
|
+ # ODPS 查询是阻塞调用,放到线程里避免阻塞事件循环
|
|
|
+ demand_schedule_cluster_platform_list = await asyncio.to_thread(_get_demand_schedule_cluster_platform_list)
|
|
|
+ if not demand_schedule_cluster_platform_list:
|
|
|
return
|
|
|
|
|
|
now = datetime.now(BEIJING_TZ)
|
|
|
- for item in DEMAND_SCHEDULE_CLUSTER_PLATFORM_LIST:
|
|
|
+ for item in demand_schedule_cluster_platform_list:
|
|
|
cluster_name = item.get("cluster_name")
|
|
|
platform_type = item.get("platform_type")
|
|
|
+ count = item.get("count")
|
|
|
if not cluster_name or platform_type not in ("piaoquan", "changwen"):
|
|
|
continue
|
|
|
|
|
|
@@ -148,8 +166,8 @@ async def demand_scheduled_run_once() -> None:
|
|
|
print(f"[scheduler] skip: cluster={cluster_name}, platform={platform_type} (today has status 0/1)")
|
|
|
continue
|
|
|
|
|
|
- print(f"[scheduler] run: cluster={cluster_name}, platform={platform_type}")
|
|
|
- await demand_start_sync(cluster_name=cluster_name, platform_type=platform_type) # 串行执行
|
|
|
+ print(f"[scheduler] run: cluster={cluster_name}, platform={platform_type}, count={count}")
|
|
|
+ await demand_start_sync(cluster_name=cluster_name, platform_type=platform_type, count=count) # 串行执行
|
|
|
|
|
|
|
|
|
_demand_scheduler: Optional[Any] = None
|
|
|
@@ -164,6 +182,10 @@ async def _demand_scheduler_job() -> None:
|
|
|
"""
|
|
|
if _demand_scheduler_lock.locked():
|
|
|
return
|
|
|
+ # 指定日期跳过:北京时间 2026-04-08 不执行定时任务
|
|
|
+ if datetime.now(BEIJING_TZ).date() == datetime(2026, 4, 8).date():
|
|
|
+ print("[scheduler] skip: 2026-04-08")
|
|
|
+ return
|
|
|
async with _demand_scheduler_lock:
|
|
|
await demand_scheduled_run_once()
|
|
|
|
|
|
@@ -193,6 +215,7 @@ async def demand_start(req: DemandStartRequest):
|
|
|
await run_demand(
|
|
|
req.cluster_name,
|
|
|
req.platform_type,
|
|
|
+ req.count,
|
|
|
execution_id=execution_id,
|
|
|
task_id=task_id,
|
|
|
)
|
|
|
@@ -277,11 +300,11 @@ def demand_task_status(task_id: int, max_log_chars: int = 2000):
|
|
|
|
|
|
@app.get("/demand/tasks")
|
|
|
def demand_tasks(
|
|
|
- status: Optional[int] = None,
|
|
|
- name: Optional[str] = None,
|
|
|
- platform_type: Optional[str] = None,
|
|
|
- page: int = 1,
|
|
|
- page_size: int = 20,
|
|
|
+ status: Optional[int] = None,
|
|
|
+ name: Optional[str] = None,
|
|
|
+ platform_type: Optional[str] = None,
|
|
|
+ page: int = 1,
|
|
|
+ page_size: int = 20,
|
|
|
):
|
|
|
where_parts: list[str] = []
|
|
|
where_params: list = []
|
|
|
@@ -331,4 +354,3 @@ def run_server():
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
run_server()
|
|
|
-
|