Files
yml2213 55f899c615 feat(automation): 拆开「多久跑一次」与「同一账号多久重检」—— 调度频率终于可配
用户反馈:「单账号重检间隔(小时) 很别扭,直接设置多久跑一次、一次跑多少个更符合直觉」。

**对,而且比"别扭"更严重:调度频率以前根本改不了。**

## 问题:两个概念挤在一个字段里

`_run_one` 里原本写着:

    job.next_run_at = finished + timedelta(seconds=JOB_INTERVAL_SECONDS)   # 硬编码 300 秒

也就是不管界面上填什么,下一轮永远是「跑完 + 5 分钟」。
而界面那个「单账号重检间隔(小时)」对应的是 `interval_seconds` ——
它只被作业**自己的选行逻辑**使用("这行多久该重检"),**完全不参与调度**。

于是出现最坏的情况:**看起来能配调度,其实配的是一个不相干的参数**。
上一轮我还拿它算过吞吐("10 分钟一轮"),算错了 —— 已在调度器注释里纠正。

## 拆法

| 概念 | 字段 | 界面 |
| --- | --- | --- |
| **多久跑一次** | `run_interval_seconds`(迁移 0051,默认 300)| 「多久跑一次(分钟)」|
| 同一账号多久重检 | `interval_seconds`(不变)| 「同一账号多久重检(小时)」|

- `next_run_at = finished + run_interval_seconds`(有下限 30 秒,避免忙轮询)
- 接口:`GET` 返回新字段、`PATCH` 可改
- 前端:两个输入框分开,并把原来那段绕口的 tooltip
  ("它不决定调度频率 —— 调度周期见页面顶部说明")改掉 ——
  那句话本身就是这个设计缺陷的自白

## 默认 300 秒

与改动前**实际行为一致** —— 不会因为这次迁移让已有作业突然变快或变慢。
想调快就自己填(比如「账号资料定时补全」填 5 分钟 + 每轮 400 条 ≈ 3 小时补完)。

## ⚠️ 顺带说明一个你截图里可能看到的现象

截图里「账号资料定时补全」显示的是 **0.5 小时 / 30 条** —— 那是我**最初的默认值**。
因为 `ensure_jobs` **只创建不更新**,我后面改成 10 分钟/400 **不会作用到已存在的行**。
这是刻意的(否则会覆盖运维的手工调整),但意味着**默认值改了要手动在界面上改**,
或者删掉那行让 `ensure_jobs` 重建。现在有了「多久跑一次」这个框,直接填就行。

## 测试(+3)

- 下一轮按**运行间隔**排,不是按「同一行重检间隔」(两个值刻意设成不同来钉住)
- 不填时默认 300 秒(保持旧行为)
- 过小的间隔被夹到下限

## 验证

TZ=Asia/Shanghai **639 passed / 6 skipped**;ruff 全绿;前端 build 通过、lint 0 errors。
2026-10-04 21:30:13 +08:00

65 lines
1.9 KiB
Python
Raw Permalink 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.
"""作业的「运行间隔」独立出来:`automation_jobs.run_interval_seconds`
## 问题
界面上只有一个「单账号重检间隔(小时)」,但它其实承担了两个互不相干的概念,
而且**调度频率根本改不了**:
| 概念 | 之前 | 之后 |
| --- | --- | --- |
| **多久跑一次** | **硬编码** `JOB_INTERVAL_SECONDS`(5 分钟)| `run_interval_seconds` |
| 同一行多久重检 | `interval_seconds` | `interval_seconds`(不变,只是不再兼任调度)|
`_run_one` 里原本写着:
job.next_run_at = finished + timedelta(seconds=JOB_INTERVAL_SECONDS)
也就是不管在界面上填什么,下一轮永远是「跑完 + 5 分钟」。
用户反馈「直接设置多久跑一次、一次跑多少个更符合直觉」—— 对。
默认 300 秒,与改动前的实际行为一致(不会因为这次迁移让已有作业突然变快/变慢)。
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
revision: str = "20261004_0051"
down_revision: str | None = "20261004_0050"
branch_labels: str | None = None
depends_on: str | None = None
COLUMN = "run_interval_seconds"
def _column_exists(name: str) -> bool:
conn = op.get_bind()
count = conn.execute(
sa.text(
"SELECT COUNT(*) FROM information_schema.columns "
"WHERE table_schema = DATABASE() "
"AND table_name = 'automation_jobs' AND column_name = :name"
),
{"name": name},
).scalar()
return bool(count)
def upgrade() -> None:
if not _column_exists(COLUMN):
op.add_column(
"automation_jobs",
sa.Column(
COLUMN,
sa.Integer(),
nullable=False,
server_default="300",
comment="多久跑一次(秒);与「同一行多久重检」是两回事",
),
)
def downgrade() -> None:
op.drop_column("automation_jobs", COLUMN)