你写的 0 点,可能不是服务器的 0 点
一、你写的 0 点,可能不是服务器的 0 点
这是半夜失败率最高的原因,也是最容易被忽略的。容器镜像默认是 UTC,crontab 按进程自身的时区解析表达式,你在本地 date 看到的是北京时间,容器里跑出来的却是 UTC 16:00。更隐蔽的是:把 TZ=Asia/Shanghai 写在脚本第一行是无效的,因为 cron 在启动子进程之前就已经解析完时间了。
- 先确认:
docker exec -it xxx date,以及在 cron 里加一条* * * * * date >> /tmp/tz.log对比。 - 正确做法:在 crontab 顶部写
TZ=Asia/Shanghai(部分 cron 实现支持CRON_TZ),或者干脆在编排层给容器设TZ环境变量。 - 夏令时地区还要注意:
0 2 * * *在春季时钟前跳的那天根本不会触发,秋季则可能触发两次。改用systemd timer的Persistent=true,关机或跳过的任务会在开机后补跑一次。
二、凌晨是全公司最拥挤的时间窗口
你以为半夜机器空闲,实际上 00:00–03:00 是所有默认配置的集中爆发点:数据库全量 mysqldump、logrotate 切割压缩、云厂商磁盘快照、ES 索引滚动、K8s 镜像预热,全都挤在这三小时。
典型症状是任务本身逻辑没错,但报 Lock wait timeout exceeded、connection refused、S3 上传超时。我们遇到过一次:备份任务把磁盘 IO 打满,导致同一时刻的报表任务读配置表超时,白天重跑一次就正常。
- 错峰:把非强时效任务挪到 04:00 之后,或用
sleep $((RANDOM % 600))打散整点并发。 - 降优先级:
nice -n 10 ionice -c2 -n7 python job.py。 - 给数据库连接显式设置
connectTimeout和socketTimeout,不要用默认的无限等待。
三、跨天那一刻,日期变量会“变心”
23:50 启动、跑 20 分钟的任务,会在执行途中跨过零点。如果脚本里多处调用 date +%Y%m%d,前半段写到昨天的分区,后半段写到今天的,清理任务再按“昨天”去删,数据就丢了。
修法很简单:脚本开头只取一次,后续全部复用——RUN_DATE=$(date +%F),并且显式传参给下游。
另一个半夜专属问题是任务重叠:前一次没跑完,下一次又被拉起,两个进程抢同一批数据。别用 ps aux | grep 判断,会有竞态:
flock -n /var/lock/report.lock -c 'python report.py',拿不到锁直接退出。- K8s CronJob 用
concurrencyPolicy: Forbid配合startingDeadlineSeconds。 - 无论如何都要保证任务幂等,失败重跑不会产生重复数据。
四、cron 的 shell 不是你的 shell
“我手动跑明明没问题”几乎都出在这里。cron 的 PATH 通常只有 /usr/bin:/bin,node、pyenv、nvm 一律找不到;它也不加载 .bashrc / .profile,所以 DB_PASSWORD、API_KEY 全是空的——白天你手动测试时有,半夜自然就失败。
- 脚本首行
#!/bin/bash后立刻加set -euo pipefail,避免静默失败。 - 需要环境变量就显式
source /etc/profile.d/app.sh,不要指望 shell 帮你加载。 - 所有命令写绝对路径,
cd "$(dirname "$0")"固定工作目录。 - 输出必须重定向:
>> /var/log/report.log 2>&1,否则报错信息无处可寻。
五、没有观测的定时任务等于不存在
cron 默认把 stdout 通过本地 MTA 发邮件,容器里没有 MTA,输出就被直接丢弃。所以很多任务不是“半夜失败”,而是失败了三个月没人知道。
真正该监控的不是进程是否在跑,而是最后一次成功时间。把每次执行的 exit code、耗时、处理条数打点到 Prometheus Pushgateway 或一张 job_runs 表,再用规则告警:“last_success_at 距今超过 26 小时”。这能同时覆盖“跑失败”和“根本没跑”两种情况——后者其实更常见,比如机器被回收、cron 文件被覆盖、镜像更新后任务没带上。
- 失败兜底:
python job.py || curl -s -X POST "$ALERT_WEBHOOK" -d "job=report failed"。 - 记录耗时趋势,任务从 2 分钟涨到 40 分钟时,你会在它真正超时之前收到信号。
- 点赞
- 收藏
- 关注作者
评论(0)