360 Secure SkillHub
360 安全技能中心

unattended-task-pitfalls

基于真实事故复盘,面向 cron、定时备份和自动报告等无人值守任务,给出后台执行、产物验证、状态写入、隔离会话取证与通知设计规则,并提供归档验证参考脚本。

mowenqwq
mowenqwq
热度 16.55
最近更新 2026-08-31 00:14:33
分类:自动化依赖:代码执行 / 读写文件应用场景:DevOps / 工作流 / 自动化脚本 / 报告撰写

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add unattended-task-pitfalls
Metadata
name
unattended-task-pitfalls
description
Hardening playbook for AI agent unattended/scheduled tasks (cron jobs, scheduled backups, auto-reports). Real incident-derived rules on background execution, artifact verification, isolated-session context blindness, notification design, and self-healing retries. Use when building or debugging cron/scheduled/automated agent tasks, "task failed but reported success" issues, corrupted backup artifacts, or silent misjudgment in scheduled summarization/archival jobs.

无人值守自动任务加固经验库(Unattended Task Pitfalls)

来源:一个 AI agent 工作区的真实事故记录(2026-08 两次备份损坏事故 + cron 总结误判事故复盘)。适用任何带定时任务的 agent 环境。

核心命题:无人值守链路里,操作纪律会失效,只有代码能兜底。

§0 使用说明

  • 搭建新的定时/自动化任务前 → 通读 §1-§3(防事故)
  • 定时任务出现"结果不对但显示成功" → §3(验证链)+ §4(隔离会话)
  • 排查"命令报错但其实执行了" → §2.3
  • 设计任务的通知行为 → §5

§1 核心哲学:记忆型教训在无人值守场景必然失效

真实事故:08-27 备份产出损坏文件上传云端,教训"gzip -t 验证后才能上传"被记入 agent 长期记忆。08-30 定时任务再次产出 528MB 截断坏文件(正常 911MB)并上传——因为 cron 会话读不到"操作纪律",纪律只对在线的 agent 有效。

结论:

  1. 凡是"以后要注意 XX"类教训,先问:能不能写成代码? 能写进脚本的一律写进脚本
  2. 记忆/文档只作人侧兜底,不是无人值守链路的防线
  3. 判断一个防护是否有效:假设 agent 完全不在线,脚本独自运行,这个防护还在不在?

§2 执行层:长任务怎么跑

§2.1 后台化(防进程被杀)

  • 长任务(打包/上传/批量处理)禁止在前台直接跑:平台网关常有 2-10 分钟超时,超时杀进程 → 留下半成品文件
  • 标准模式:setsid nohup <cmd> > /tmp/task.log 2>&1 &,然后轮询日志/文件时间戳确认进度
  • 佐证数据:同一个备份脚本,前台跑两次两次被杀,后台跑零事故

§2.2 半成品的危害大于失败

进程被杀不是"任务失败",而是"任务产出了一个损坏的产物"。若下游逻辑(上传/清理/状态标记)不感知损坏,坏产物会流转进正式链路(本例:坏备份被上传到云端"永久保留"区)。

§2.3 网关 504 ≠ 命令失败

  • 工具调用层报 504 Gateway Timeout,底层命令可能已经执行成功(尤其 setsid 后台任务不受会话死亡影响)
  • 正确处置:先 ps 查进程、查产物文件时间戳,确认实际状态再决定是否重发
  • 危险反面案例:盲目重发副作用命令(删除/上传/发布)→ 重复执行事故
  • 504 后重发的三个前置检查:进程在不在 / 产物变没变 / 任务是否幂等

§3 产物验证链(核心章节)

以"打包 → 上传 → 标记成功"类任务为例,完整验证链五环节:

§3.1 打包后本地验证

gzip -t <archive>      # 压缩流完整性(截断文件在此暴露)
tar -tzf <archive> > /dev/null   # 归档结构抽查(防 tar 头损坏)

两者都过才算产物有效。gzip -t 约 8 秒 / 900MB,成本可忽略。

§3.2 验证不过 → 不上传 + 不更新状态

  • 上传前验证失败:跳过上传,保持上一份好的远端文件不动
  • 状态文件(last_run 时间戳)只在"上传成功"后写入——失败则下轮自动重试,不会因状态已标记而跳过

§3.3 "已存在则跳过"短路必须先验证

增量/幂等脚本常见 if 存在今日产物: return。坑:产物存在 ≠ 产物完好。正确写法:

if exists(today_file):
    if verify(today_file): return today_file   # 真完成,跳过
    else: os.remove(today_file)                # 损坏,删除重打包(自愈)

真实踩坑:重跑修复任务时被短路逻辑复用坏文件,幸好上传前验证兜住。

§3.4 远端核对(不下载大文件)

WebDAV 用 PROPFIND + 正则取 getcontentlength,与本地字节数比对即可确认远端文件是否同坏。同类协议找等价的元数据接口,禁止为了验证下载 500MB。

§3.5 参考实现

见 scripts/verify_archive.py——打包验证 + 已存在自愈 + 上传成功才写状态的最小可复用模板。


§4 隔离会话:cron 看不到你以为它看得到的东西

真实事故:每日总结 cron 连续两天误判"全天无对话,静默结束"——实际当天有多轮主会话交互。根因:cron 会话与主会话隔离,对话历史、记忆快照可能都不在上下文里(且部分平台对话存储对 cron 完全不可见)。

§4.1 文件系统证据法

cron 里下"无活动"结论前,强制扫一遍文件系统:

find <workspace> -newermt "今日00:00" ! -newermt "明日00:00" -type f

有当日修改的文件 → 有活动,去读文件内容还原事实。

§4.2 排除自动产物

每次会话启动都会刷新时间戳的文件(.env、自动生成的 README、缓存)不算人类活动证据,先建排除表再判断。

§4.3 时间归属约定

与用户约定的时间归属规则(如"凌晨 0-2 点归前一天")要在归档类任务里显式实现,否则跨日任务的时间戳归属会跟主会话记录打架。


§5 通知设计

§5.1 两类机制的分工

机制 语义 适用
定时任务(cron) 无条件通知:每次运行必发结果 结果本身有价值(备份/日报)
心跳(heartbeat) 条件通知:有情况才发 多检查项聚合、需要会话上下文

§5.2 通知格式纪律

  • 结果 + 关键指标 + 异常标注(✓/✗),失败必附原因和日志位置
  • 自动任务输出禁用拟人内容("早点睡哦"类关怀语)——任务运行时用户根本不在线,出现只会诡异
  • 高频无变化任务设静默档(如 skill 更新扫描:无更新不上报),避免通知疲劳

§6 交叉验证与任务生命周期

§6.1 自动任务的产物也要被自动检查

单一任务的自我报告不可信(本例:备份任务报"上传成功",实际传的是坏文件)。模式:另一个任务例行抽查产物(每日总结任务顺手 gzip -t 备份——这是发现 08-30 事故的唯一渠道)。至少给关键产物配一条独立验证路径。

§6.2 一次性任务自删

定时复查类任务(如"45分钟后确认发布状态")完成后应自删,避免次日重复执行。一次性触发用 at 型调度,勿用 every 型。

§6.3 失败的默认出口

无人值守任务失败的默认行为 = 记录日志 + 通知用户 + 保留现场。不要在失败路径上做自动重试以外的主观决策(删数据/覆盖文件/换路径),这些留给下一次有人在线时处理。


附:事故案例速查

日期 事故 对应章节
08-27 备份前台跑被网关杀,坏文件上传云端 §2.1 §2.2 §3.1
08-30 同款事故复发(教训只在记忆未进代码) §1
08-30 重跑被"已存在跳过"复用坏文件 §3.3
08-30 网关 504 但命令实际已执行 §2.3
08-24/25 cron 总结误判"全天无对话" §4

更新日志

  • v1.0.0(2026-08-31):首版。两次备份事故 + cron 误判事故的完整复盘沉淀