1
This commit is contained in:
@@ -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 传入 handler,handler 在最终 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
|
||||
|
||||
Reference in New Issue
Block a user