自动化与投递
没有守护进程。调度交给主机调度器;工具提供生成器和 --print 模式,未经确认不会写入任何内容。同一条报告流水线可从 cron、systemd、Task Scheduler 或 CI 任务运行。
相关页面:报告与差异、数据源与配额、抓取与审计、MCP 与智能体技能。
安装或预览计划任务
lv24-seo schedule install --kind weekly --cron "0 6 * * 1" --config ./seo.toml --print
lv24-seo schedule install --kind daily --cron "0 6 * * *" --config ./seo.toml
lv24-seo schedule print --cron "0 6 * * 1" --target systemd --json默认 weekly 为 0 6 * * 1,daily 为 0 6 * * *。生成的命令是 report weekly --send --json;daily 类型会追加 --days 1 --lag-days 0。绝对 --config 路径和配置目录会作为工作目录写入,因此自定义文件名、带空格的路径或同一目录中的多个配置都能继续工作。
schedule install 没有 --target 标志:它会检测主机后端。schedule print 接受 --target cron|systemd|windows,只渲染而不触碰主机。没有 schedule status 命令;请用 crontab -l、systemctl --user list-timers 或任务计划程序检查主机。
产物
| 目标 | 产物 | 位置 | 时区行为 |
|---|---|---|---|
cron | 带 CRON_TZ=<zone> 和 cd 前缀的受管 crontab 块 | 当前用户的 crontab | CRON_TZ 受 Vixie/ISC cron 支持;其他守护进程使用主机时间 |
systemd | 用户单元 lv24-seo-<kind>.service 和 .timer | ~/.config/systemd/user(感知 XDG) | OnCalendar 包含配置的 IANA 时区 |
windows | UTF-16 Task Scheduler XML | %APPDATA%\lv24-seo\schedule | StartBoundary 携带解析后的 UTC 偏移 |
cron 块由 # >>> lv24-seo:<name> >>> 和 # <<< lv24-seo:<name> <<< 界定。重新安装会替换该任务的所有受管块。缺少结束标记的损坏块会被视为延伸到下一个受管标记或 EOF,因此 schedule install 会修复文件,而不是追加重复任务。
只有简单的 cron 形式(M H * * * 和 M H * * DOW)能转换为 systemd 或 Windows。其他形式会被拒绝,而不是静默改期。未知或不可用的时区会在安装前被拒绝。
安装结果始终带有 warnings 列表说明后端限制:cron 可能忽略 CRON_TZ,Windows XML 编码固定偏移而非 IANA 时区,因此季节性 DST 变化需要复核。Windows 使用 tzdata(Windows 自带)。systemd 通过 systemctl --user daemon-reload 和 systemctl --user enable --now 启用计时器。
建议频率
| 任务 | 时间 | 原因 |
|---|---|---|
report weekly --send | 周一 06:00 | GSC 数据有 2–3 天延迟;周一较稳定 |
crawl --start URL | 每周,报告之后 | 让抓取证据贴近报告窗口 |
auth status | 每周 | 确认每个提供商令牌的存在与来源 |
| CrUX 字段数据 | 每周 | 28 天滚动窗口;每日轮询没有额外价值 |
每个周期只保留一个计划任务。投递是至少一次,因此两个重叠的计划即使有账本也可能把同一份报告发送两次。
Email 与 Telegram
Email 使用 587 端口的 SMTP、STARTTLS 和会验证证书的 TLS 上下文。TLS 失败后绝不会登录。消息为 multipart/alternative:产品 HTML 模板加上相同内容的 78 列纯文本,主题为不超过 78 个字符的本地化单行文本。
模板是 600px 卡片,仅使用内联 CSS,没有外部图片、样式表、脚本、跟踪像素或远程字体。未知 KPI 显示为本地化的“无数据”,而不是 0。Metrika 显示为会话,不是点击。问题部分为空时会说明未提供问题数据,而不是声称站点干净。限制和警告会去重;提供商原文保持原语言,并在报告本地化时标注。页脚包含属性 id、UTC 生成时间和“generated by lv24-seo”。
Telegram 通过 Bot API sendMessage 发送相同的 78 列本地化文本。HTTP 4xx/5xx、超时和格式错误的响应都会标记为 failed,绝不记录为已发送。
只有 email 和 Telegram 两个渠道。没有 Resend 或 Brevo 适配器,也没有 --channel github。
在 seo.toml 的 [report.email] 和 [report.telegram] 中配置投递。SMTP 密码和 Telegram 机器人令牌来自 auth set --provider smtp|telegram,绝不来自配置文件。--send 是必需的;生成的计划任务已经包含它。
幂等性
报告投递通过 sends 账本实现幂等,账本在 (kind, property, period, channel, content_hash) 上唯一。哈希覆盖标题和各个部分以及规范化后的渲染语言;generated_at 和诊断信息不参与。英语不在哈希中包含语言,因此升级不会重发已经投递的英语周期。
only_on_change 在内容哈希已投递时跳过发送(already_sent)。当没有任何变化达到 report.thresholds 时,实质性门槛会跳过发送(no_material_change)。门槛先于语言哈希运行,因此当周期没有实质性变化时,单纯切换语言仍可能被抑制。
投递是每渠道至少一次。传输结果不明确时会标记 failed 且不记录,因此下一次运行可能重复投递。进程崩溃后 SMTP 和 Bot API 都不提供恰好一次。数据库会串行化投递尝试,并可能阻塞其他写入者直到传输超时。
写入闸门
提供商写入与报告投递分离。CLI 使用试运行加显式应用:
- 设置
LV24_SEO_WRITE_SECRET并用--allow-write运行写入命令。没有密钥时闸门以WRITE_DISABLED拒绝。 - 检查计划、
plan_hash和confirm_token。令牌是对动作、目标、计划哈希和过期时间的 HMAC,有效期为 300 秒。 - 使用相同标志加
--confirm <token>应用。计划变化、密钥错误、令牌格式错误或过期都会以CONFIRM_REQUIRED失败。
工作区初始化后,闸门支持 pending-to-sent 幂等声明:CLI 附加 SQLite 账本,提供商调用失败会释放声明并允许重试;已完成或仍在进行中的声明视为重复并返回 skipped。没有数据目录时仍会应用,但信封会警告:在令牌五分钟有效期内没有重放保护。试运行不打开账本,也不创建数据库。崩溃可能留下没有 TTL 的 pending 声明(0.5.2),在操作员释放前会被视为进行中。
0.5.2 中只有 IndexNow 真正提交。GSC 站点地图提交和 Yandex 重新抓取会以 WRITE_DISABLED 拒绝,而不是假装成功。MCP 写入工具要求 allow_write=true;它们在本构建中的处理器也未接通,因此返回 WRITE_DISABLED。
GitHub Actions
产品仓库提供每周 workflow 配方:examples/github-actions/seo-weekly.yml。把它复制到你的站点仓库,而不是工具仓库。
on:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:
permissions:
contents: read该配方使用标准 ubuntu-latest 运行器、单个任务、15 分钟超时、concurrency 组和较短的产物保留期。在公开仓库加标准运行器时成本为 $0。私有仓库会消耗包含或计费的 Actions 分钟和存储;更大运行器、矩阵和付费附加项不属于零支出路径。
任务通过 actions/cache 恢复 data/seo.sqlite3(以及 -wal 和 -shm),创建数据目录,然后运行:
uvx --from lv24-seo lv24-seo report weekly --send --json提供商和投递凭据来自仓库 secret。非秘密标识符保留在已提交的 seo.toml 中。GitHub cron 始终是 UTC,因此要显式换算目标本地时间。
时区
report.timezone 是 IANA 时区(默认 Europe/Minsk)。它驱动报告和 stats 窗口、MCP 默认窗口以及本地日期边界。提供商数据仍按日期存储,不做转换。
调度后端在支持时应用该时区,不支持时给出警告。无效时区会在配置校验时以 CONFIG_INVALID 失败,绝不会被静默替换。DST 转换后要复核 Windows 任务,并在依赖 CRON_TZ 前确认已安装的 cron 守护进程支持它。
Source: _source/engine-scheduling.md, _source/engine-cli.md, _source/engine-config.md.