关键命令失败需先判错再重试,仅对临时故障(如超时、503/504)重试3次并指数退避;永久错误(如语法错、4xx)禁止重试;须加超时、唯一ID、flock防护,并在最终失败时归档日志并告警。

关键命令失败时不能无差别重试,得先判断错误性质,再决定是否重试、重试几次、怎么等。核心是“该重才重”,避免把语法错误当网络抖动来反复执行。
识别哪些错误值得重试
临时性故障可以重试,永久性问题重试只会浪费资源甚至引发新问题:
- 适合重试:连接超时(timeout)、连接被拒(Connection refused)、路由不可达(No route to host)、HTTP 503 或 504
- 不该重试:语法错误(syntax error)、权限不足(Permission denied)、路径不存在(No such file or directory)、密钥解密失败、返回 HTTP 400/401/403/404
在脚本中结合退出码和 stderr 内容做双重判断:
if [[ $? -ne 0 ]] && grep -q -E "(timeout|refused|unreachable|503|504)" "$LOG_TMP"; then should_retry=true; fi用指数退避控制重试节奏
固定间隔容易撞上服务限流或触发雪崩。推荐最多 3 次,每次等待时间递增并加随机抖动:
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
- 第 1 次失败后等约 1 秒
- 第 2 次等约 2 秒
- 第 3 次等约 4 秒
抖动示例(防并发同步):
sleep $(echo "scale=1; $((2**attempt)) * (0.8 + $RANDOM/32767*0.4)" | bc)循环结构建议用 for:
for ((i=1; i<=3; i++)); do ... if [[ $? -eq 0 ]]; then break; fi; done加防护层防止重试本身出问题
没保护的重试可能卡死、并发冲突或覆盖日志:
- 给主命令加硬性超时:
timeout 300s your_command - 每次运行生成唯一 ID:
run_id=$(date +%s)-$$,用于日志名、锁文件、临时目录 - 用 flock 防止 cron 多次触发并行:
exec 200>/tmp/mytask.lock; flock -n 200 || exit 1
失败后必须归档并告警
重试耗尽说明问题无法自愈,必须留痕并通知人:
- 把原始命令、完整 stderr、环境变量快照打包存入:
/var/log/mytask/failures/${run_id}_attempt3.tar.gz - 只在最终失败时发通知:用 mail 发邮件,或 curl 推送钉钉/企微机器人
- crontab 条目末尾统一重定向日志:
0 2 * * * /opt/scripts/task.sh >> /var/log/task.log 2>&1

















