凌晨 2 点的对账脚本跑了小半年没出事,10 月 13 号早上客户财务发来截图:同一天的汇总有两份,金额差了一笔。
1. 第一反应是脚本有 bug
查了半小时脚本,幂等逻辑看着没问题,按日期加门店号做了唯一键。翻执行日志才发现,2:00 和 2:01 各有一条完整记录,两次都跑完了。
2. crontab 里同一行贴了两遍
登服务器 crontab -l,一屏 30 多行,第 8 行和第 15 行一模一样。之前加一个临时补数任务时复制粘贴,补完忘了删,两次间隔刚好 1 分钟。第二遍跑的时候第一批数据已经写库,唯一键挡住了明细,但汇总表是按「本次运行」插的,于是多了一行。
3. 为什么唯一键没拦住汇总
明细表有 UNIQUE(date, store_id),汇总表没有,它存的是每次运行的时间、条数、合计。设计的时候默认「一天只会跑一次」,这个默认没写进任何约束里。补上了 UNIQUE(run_date)。
4. 加文件锁
脚本开头加一行 flock:拿不到 /var/lock/daily_recon.lock 就直接退出并记一条日志。这样就算将来又贴重复,第二个进程也进不来。锁文件放 /var/lock,重启会清,不会锁死。
5. 每次运行先拿 run_id
现在脚本第一件事是往 run_log 表插一条,拿到自增 id,后面所有写入都带这个 run_id。出问题时按 id 一查,这次跑了哪些步骤、写到哪张表、几点开始几点结束,一目了然。那次如果有这东西,不用猜。
6. crontab 收进 Git
以前服务器上的 crontab 是谁想改谁 ssh 上去 crontab -e。现在仓库里放一份 crontab 文件,改完走一遍部署脚本下发,服务器上的那份只读。diff 一眼能看出多了哪行。
那两张表
客户财务后来把重复的汇总删了一行,没造成别的影响。我们把 10 月 13 号记进了内部的一个小本子,标题就四个字:别信默认。

