Files
Neo-ZQYY/apps/backend/app/services/task_expiry.py

118 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
有效期轮询器Task Expiry Checker
每小时运行一次,检查 expires_at 不为 NULL 且已过期的 active 任务,
将其标记为 inactive 并记录 history。
由 trigger_jobs 中的 task_expiry_check 配置驱动。
"""
import json
import logging
logger = logging.getLogger(__name__)
def _get_connection():
"""延迟导入 get_connection避免模块级导入失败。"""
from app.database import get_connection
return get_connection()
def _insert_history(
cur,
task_id: int,
action: str,
old_status: str | None = None,
new_status: str | None = None,
old_task_type: str | None = None,
new_task_type: str | None = None,
detail: dict | None = None,
) -> None:
"""在 coach_task_history 中记录变更。"""
cur.execute(
"""
INSERT INTO biz.coach_task_history
(task_id, action, old_status, new_status,
old_task_type, new_task_type, detail)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""",
(
task_id,
action,
old_status,
new_status,
old_task_type,
new_task_type,
json.dumps(detail) if detail else None,
),
)
def run() -> dict:
"""
有效期轮询主流程。
1. SELECT id, task_type FROM biz.coach_tasks
WHERE expires_at IS NOT NULL AND expires_at < NOW() AND status = 'active'
2. 逐条 UPDATE status = 'inactive'
3. INSERT coach_task_history (action='expired')
每条过期任务独立事务,失败不影响其他。
返回: {"expired_count": int}
"""
expired_count = 0
conn = _get_connection()
try:
# 查询所有已过期的 active 任务
with conn.cursor() as cur:
cur.execute(
"""
SELECT id, task_type
FROM biz.coach_tasks
WHERE expires_at IS NOT NULL
AND expires_at < NOW()
AND status = 'active'
"""
)
expired_tasks = cur.fetchall()
conn.commit()
# 逐条处理,每条独立事务
for task_id, task_type in expired_tasks:
try:
with conn.cursor() as cur:
cur.execute("BEGIN")
cur.execute(
"""
UPDATE biz.coach_tasks
SET status = 'inactive', updated_at = NOW()
WHERE id = %s AND status = 'active'
""",
(task_id,),
)
_insert_history(
cur,
task_id,
action="expired",
old_status="active",
new_status="inactive",
old_task_type=task_type,
new_task_type=task_type,
)
conn.commit()
expired_count += 1
except Exception:
logger.exception("处理过期任务失败: task_id=%s", task_id)
conn.rollback()
finally:
conn.close()
logger.info("有效期轮询完成: expired_count=%d", expired_count)
return {"expired_count": expired_count}