This commit is contained in:
Neo
2026-03-15 10:15:02 +08:00
parent 2dd217522c
commit 72bb11b34f
916 changed files with 65306 additions and 16102803 deletions

View File

@@ -31,6 +31,20 @@ def register_job(job_type: str, handler: Callable) -> None:
_JOB_REGISTRY[job_type] = handler
def update_job_last_run_at(cur, job_id: int) -> None:
"""
在 handler 的事务内更新 last_run_at。
handler 在最终 commit 前调用此函数,将 last_run_at 更新纳入同一事务。
handler 成功 → last_run_at 随事务一起 commit。
handler 失败 → last_run_at 随事务一起 rollback。
"""
cur.execute(
"UPDATE biz.trigger_jobs SET last_run_at = NOW() WHERE id = %s",
(job_id,),
)
def fire_event(event_name: str, payload: dict[str, Any] | None = None) -> int:
"""
触发事件驱动型任务。
@@ -38,6 +52,10 @@ def fire_event(event_name: str, payload: dict[str, Any] | None = None) -> int:
查找 trigger_condition='event' 且 trigger_config.event_name 匹配的 enabled job
立即执行对应的 handler。
事务安全:将 job_id 传入 handler由 handler 在最终 commit 前
更新 last_run_at保证 handler 数据变更与 last_run_at 在同一事务中。
handler 失败时整个事务回滚last_run_at 不更新。
返回: 执行的 job 数量
"""
conn = _get_connection()
@@ -55,6 +73,7 @@ def fire_event(event_name: str, payload: dict[str, Any] | None = None) -> int:
(event_name,),
)
rows = cur.fetchall()
conn.commit()
for job_id, job_type, job_name in rows:
handler = _JOB_REGISTRY.get(job_type)
@@ -64,18 +83,11 @@ def fire_event(event_name: str, payload: dict[str, Any] | None = None) -> int:
)
continue
try:
handler(payload=payload)
# 将 job_id 传入 handlerhandler 在最终 commit 前更新 last_run_at
handler(payload=payload, job_id=job_id)
executed += 1
# 更新 last_run_at
with conn.cursor() as cur:
cur.execute(
"UPDATE biz.trigger_jobs SET last_run_at = NOW() WHERE id = %s",
(job_id,),
)
conn.commit()
except Exception:
logger.exception("触发器 %s 执行失败", job_name)
conn.rollback()
finally:
conn.close()
@@ -87,6 +99,11 @@ def check_scheduled_jobs() -> int:
检查 cron/interval 类型的到期 job 并执行。
由 Scheduler 后台循环调用。
事务安全:将 conn 和 job_id 传入 handler由 handler 在最终 commit 前
更新 last_run_at 和 next_run_at保证 handler 数据变更与时间戳在同一事务中。
handler 失败时整个事务回滚。
返回: 执行的 job 数量
"""
conn = _get_connection()
@@ -104,6 +121,7 @@ def check_scheduled_jobs() -> int:
""",
)
rows = cur.fetchall()
conn.commit()
for job_id, job_type, job_name, trigger_condition, trigger_config in rows:
handler = _JOB_REGISTRY.get(job_type)
@@ -111,11 +129,12 @@ def check_scheduled_jobs() -> int:
logger.warning("未注册的 job_type: %s", job_type)
continue
try:
handler()
executed += 1
# 计算 next_run_at 并更新
# cron/interval handler 接受 conn + job_id在最终 commit 前更新时间戳
handler(conn=conn, job_id=job_id)
# 计算 next_run_at 并更新(在 handler commit 后的新事务中)
next_run = _calculate_next_run(trigger_condition, trigger_config)
with conn.cursor() as cur:
cur.execute("BEGIN")
cur.execute(
"""
UPDATE biz.trigger_jobs
@@ -125,6 +144,7 @@ def check_scheduled_jobs() -> int:
(next_run, job_id),
)
conn.commit()
executed += 1
except Exception:
logger.exception("触发器 %s 执行失败", job_name)
conn.rollback()
@@ -156,6 +176,6 @@ def _calculate_next_run(
from apps.backend.app.services.scheduler import _parse_simple_cron
return _parse_simple_cron(
trigger_config.get("cron_expression", "0 4 * * *"), now
trigger_config.get("cron_expression", "0 7 * * *"), now
)
return None # event 类型无 next_run_at