系统定时任务日志持久化:新增入库与后台查询
- 新增系统任务日志表 t_system_job_logs,持久化记录每次执行结果、摘要、耗时、详情JSON\n- SystemJobLoader 注册任务时增加执行包装器:成功/失败均写入数据库日志,失败后继续抛出保证运行态状态一致\n- 系统任务后台日志接口改为查询数据库日志(不再依赖仅内存的 async_job logs),解决重启后日志丢失问题\n- 保持前端日志字段兼容,接口返回映射为 time/level/message 结构
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from datetime import datetime
|
||||
from typing import Any, Awaitable, Callable, Dict, List
|
||||
|
||||
from loguru import logger
|
||||
@@ -99,9 +101,38 @@ class SystemJobLoader:
|
||||
logger.warning(f"系统任务 {job_key} 在代码中无处理器,已跳过注册")
|
||||
continue
|
||||
|
||||
handler = definition["handler"]
|
||||
raw_handler = definition["handler"]
|
||||
|
||||
async def _wrapped_handler(_handler=raw_handler, _job_key=job_key):
|
||||
"""系统任务执行包装器:执行业务并持久化日志。"""
|
||||
started_at = datetime.now()
|
||||
try:
|
||||
result = _handler()
|
||||
# 兼容同步/异步 handler 两种写法。
|
||||
if inspect.isawaitable(result):
|
||||
await result
|
||||
duration_ms = int((datetime.now() - started_at).total_seconds() * 1000)
|
||||
self.db.create_job_log(
|
||||
_job_key,
|
||||
"success",
|
||||
"执行成功",
|
||||
detail={"job_key": _job_key},
|
||||
duration_ms=duration_ms,
|
||||
)
|
||||
except Exception as e:
|
||||
duration_ms = int((datetime.now() - started_at).total_seconds() * 1000)
|
||||
# 失败日志写库后继续抛出,让 async_job 运行态状态也能正确标记为 failed。
|
||||
self.db.create_job_log(
|
||||
_job_key,
|
||||
"failed",
|
||||
f"执行失败: {e}",
|
||||
detail={"job_key": _job_key, "error": str(e)},
|
||||
duration_ms=duration_ms,
|
||||
)
|
||||
raise
|
||||
|
||||
job_id = async_job.register_callable(
|
||||
func=handler,
|
||||
func=_wrapped_handler,
|
||||
trigger_type=row.get("trigger_type", definition["trigger_type"]),
|
||||
trigger_config=row.get("trigger_config", definition["trigger_config"]),
|
||||
job_name=row.get("name") or definition["name"],
|
||||
|
||||
Reference in New Issue
Block a user