checkpoint: 调度任务存储落 PG——jobstore 归一 default + execute 写回真实触发 + 前端 store 字典更新

- ap_scheduler: 默认分组改 SQLAlchemyJobStore on PG,删 RedisJobStore 与 redis_instance;注释/告警口径同步
- node/service: jobstore 归一 default(兼容存量 sqlalchemy 名);cron/interval/date 写回 task_node.trigger/trigger_args(前端列表可见真实触发);run_job_now 用独立临时 id,不再覆盖节点既有排程
- enums: 删 APSCHEDULER_LOCK_KEY(jobstore 落 PG 后死锁)
- sys_dict_data: sys_job_store 字典归一 default,删 sqlalchemy 档
- 前端: 任务表单 store 选项与 default 归一
This commit is contained in:
34047007@qq.com
2026-08-07 21:47:38 +08:00
parent 86126ea16f
commit 73e25050df
6 changed files with 61 additions and 46 deletions
@@ -156,6 +156,12 @@ class NodeService:
else:
raise CustomException(msg=f"不支持的触发方式: {trigger}")
# 非一次性触发写回 task_node,任务列表可展示真实触发配置;
# apscheduler_jobs 表已有完整状态,此处仅补齐业务表字段
if trigger != "now":
obj.trigger = trigger
obj.trigger_args = trigger_args
return {"job_id": id, "status": "executed", "trigger": trigger}
async def batch_set_status(self, ids: list[int], status: int) -> None:
@@ -171,14 +177,21 @@ class NodeService:
# ── NodeModel 封装的任务添加方法 ────────────────────────────
def _add_job_with_trigger(job_info: NodeModel, trigger) -> Job:
"""将 NodeModel 封装的任务添加到 APScheduler 调度器。"""
def _add_job_with_trigger(job_info: NodeModel, trigger, job_id: str | None = None) -> Job:
"""将 NodeModel 封装的任务添加到 APScheduler 调度器。
job_id 为 None 时用节点 id 作调度任务 idcron/interval/date 复用节点 id,便于原地更新);
立即执行(now)传独立临时 id,避免覆盖节点已有的定时排程。
"""
code_block = job_info.func
if not code_block or not code_block.strip():
raise ValueError("任务代码块不能为空")
jobstore = job_info.jobstore or "sqlalchemy"
jobstore = job_info.jobstore or "default"
if jobstore == "sqlalchemy":
jobstore = "default" # 存量节点 jobstore="sqlalchemy"(旧持久化 store 名)归一为统一 PG store
executor = job_info.executor or "threadpool"
job_id = job_id or str(job_info.id)
job_args = []
if job_info.args:
@@ -195,7 +208,7 @@ def _add_job_with_trigger(job_info: NodeModel, trigger) -> Job:
except json.JSONDecodeError:
raise ValueError(f"关键字参数JSON格式无效: {kwargs_str}")
SchedulerUtil.job_name_cache[str(job_info.id)] = job_info.name or ""
SchedulerUtil.job_name_cache[job_id] = job_info.name or ""
try:
job = scheduler.add_job(
@@ -203,37 +216,42 @@ def _add_job_with_trigger(job_info: NodeModel, trigger) -> Job:
trigger=trigger,
args=[str(job_info.id), code_block, *job_args],
kwargs=job_kwargs,
id=str(job_info.id),
id=job_id,
name=job_info.name,
coalesce=job_info.coalesce,
max_instances=1,
jobstore=jobstore,
executor=executor,
)
logger.info(f"任务 {job_info.id} 添加到 {jobstore} 存储器成功")
logger.info(f"任务 {job_id} 添加到 {jobstore} 存储器成功")
return job
except ConflictingIdError:
scheduler.remove_job(job_id=str(job_info.id), jobstore=jobstore)
scheduler.remove_job(job_id=job_id, jobstore=jobstore)
job = scheduler.add_job(
func=SchedulerUtil._task_wrapper,
trigger=trigger,
args=[str(job_info.id), code_block, *job_args],
kwargs=job_kwargs,
id=str(job_info.id),
id=job_id,
name=job_info.name,
coalesce=job_info.coalesce,
max_instances=1,
jobstore=jobstore,
executor=executor,
)
logger.info(f"任务 {job_info.id} 已存在,已移除旧任务并重新添加")
logger.info(f"任务 {job_id} 已存在,已移除旧任务并重新添加")
return job
def add_and_run_job_now(job_info: NodeModel) -> Job:
"""立即执行任务(加入调度器并尽快触发一次)。"""
"""立即执行任务(加入调度器并尽快触发一次)。
用独立临时 id{节点id}_run_now_{时间戳})添加一次性 date 任务:
只触发一次、跑完自动移除,不覆盖该节点已有的 cron/interval 定时排程。
"""
temp_id = f"{job_info.id}_run_now_{datetime.now().timestamp()}"
trigger = DateTrigger(run_date=datetime.now() + timedelta(seconds=0.1))
return _add_job_with_trigger(job_info, trigger)
return _add_job_with_trigger(job_info, trigger, job_id=temp_id)
def add_cron_job(