fix(automation): 修正调度口径——作业每 5 分钟跑一轮,interval_seconds 只是单行重检间隔
P1a 把两个「间隔」混成了一个:next_run_at 用的是 job.interval_seconds,于是 作业 6 小时才跑一轮、每轮 200 条 = 800 条/天,全库 12,881 条要 16 天才能过 一遍 —— 等于没巡检,与规划里「账号 6 小时内被查一次」的目标差了两个数量级。 按规划原意修正: - TICK_SECONDS 60 → 300:作业每个 tick(5 分钟)跑一轮; - next_run_at 改为 finished + TICK_SECONDS,不再用 interval_seconds; - interval_seconds 只作为「同一行多久重新检测」的选行 cutoff(选行逻辑本来就 是这么用的,无需改); - 容量口径随之更新:5 分钟一轮 × 200 条 = 40 条/分钟 ≥ 需要的 36 条/分钟, 冷启动约 5.4 小时覆盖全库,稳态每轮一百多条; - 前端标签由「巡检周期(小时)」改为「单账号重检间隔(小时)」,说明文案写清 「每 5 分钟跑一轮」,避免运维误以为是作业周期。 同步更新规划文档 §7.2/§7.3(含两个间隔不能混的说明)与附录 C 的三段上线 步骤(立即跑一次 → 每轮 50 观察 → 每轮 200 启用)。
This commit is contained in:
@@ -46,7 +46,9 @@ def register_default_jobs() -> None:
|
||||
JobSpec(
|
||||
key=CK_HEALTH_KEY,
|
||||
title="CK 自动巡检",
|
||||
# 6 小时一轮;全库 12,881 条按此反推 batch_size=200(见规划附录 C)。
|
||||
# interval_seconds = 单账号多久重新检测一次(不是作业周期;
|
||||
# 作业每个 tick 都跑)。全库 12,881 条按 5 分钟一轮、单轮 200 条
|
||||
# 反推,吞吐 40 条/分钟,够 6 小时内覆盖一遍(规划 §7.3)。
|
||||
interval_seconds=6 * 3600,
|
||||
batch_size=200,
|
||||
concurrency=5,
|
||||
|
||||
@@ -26,8 +26,16 @@ from sqlalchemy.orm import Session
|
||||
from ...database import SessionLocal
|
||||
from ...models import AutomationJob, AutomationRun
|
||||
|
||||
# 调度轮询间隔:作业间隔都以它为单位对齐(默认 6h 的作业不会差这一分钟)。
|
||||
TICK_SECONDS = 60
|
||||
# 调度轮询间隔,也是作业的运行节奏:每个 tick 跑一轮。
|
||||
#
|
||||
# 注意区分两个「间隔」:
|
||||
# - **本常量**:作业多久跑一轮(5 分钟);
|
||||
# - **job.interval_seconds**:同一行数据多久重新检测一次(默认 6h),只用于选行 cutoff。
|
||||
#
|
||||
# 分开的原因:全库 12,881 条的 CK 若想「6 小时内都被查一遍」,需要约 36 条/分钟的
|
||||
# 吞吐;按 5 分钟一轮、单轮 200 条算 = 40 条/分钟,刚好够。若把作业周期也设成 6h,
|
||||
# 就变成 200 条/6h = 800 条/天,全库要 16 天才能过一轮,等于没巡检。
|
||||
TICK_SECONDS = 300
|
||||
|
||||
TRUTHY = {"1", "true", "yes", "on"}
|
||||
|
||||
@@ -169,9 +177,9 @@ def _run_one(db: Session, job: AutomationJob, spec: JobSpec) -> dict[str, Any]:
|
||||
run.detail = counters.get("detail") or None
|
||||
|
||||
job.last_run_at = finished
|
||||
job.next_run_at = finished + timedelta(
|
||||
seconds=max(int(job.interval_seconds or spec.interval_seconds), 60)
|
||||
)
|
||||
# 下一轮固定在一个 tick 之后;interval_seconds 是「同一行多久重检」,
|
||||
# 由作业自己在选行时用,不参与调度。
|
||||
job.next_run_at = finished + timedelta(seconds=TICK_SECONDS)
|
||||
job.last_status = status
|
||||
job.last_message = message
|
||||
job.updated_at = finished
|
||||
|
||||
@@ -178,7 +178,7 @@ export default function AutomationPage() {
|
||||
showIcon
|
||||
style={{ marginBottom: 16 }}
|
||||
message="巡检只检测、不改 CK"
|
||||
description="本作业只把失效账号找出来并标记,不会替换任何 Cookie、也不会改账号状态;重登仍由人工在「CK 检测与重登」页面操作。"
|
||||
description="每 5 分钟跑一轮,每轮按「每轮条数」上限挑最久没检测的账号;「单账号重检间隔」指同一个账号最多多久重新检测一次。本作业只标记失效账号,不会替换任何 Cookie、也不会改账号状态,重登仍由人工在「CK 检测与重登」页面操作。"
|
||||
/>
|
||||
|
||||
{jobs.map((job) => (
|
||||
@@ -212,11 +212,11 @@ export default function AutomationPage() {
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={[job.key, 'interval_hours']}
|
||||
label="巡检周期(小时)"
|
||||
label="单账号重检间隔(小时)"
|
||||
>
|
||||
<InputNumber min={0.1} step={1} disabled={!canManage} />
|
||||
</Form.Item>
|
||||
<Form.Item name={[job.key, 'batch_size']} label="单轮条数">
|
||||
<Form.Item name={[job.key, 'batch_size']} label="每轮条数">
|
||||
<InputNumber min={1} max={2000} disabled={!canManage} />
|
||||
</Form.Item>
|
||||
<Form.Item name={[job.key, 'concurrency']} label="并发">
|
||||
|
||||
Reference in New Issue
Block a user