跳到主要内容

让 AI 写了个数据回补脚本,我过了三遍才敢跑

敏姐转开发
敏姐转开发

· 阅读约 3 分钟

先交代背景吧,不交代清楚我自己写着也难受。

我们模块底下有张 t_user_asset 表,记用户买的各种权益,每条有 expire_at 和 status 两个字段。历史遗留问题:大概 2023 年那会儿有个定时任务挂了大半天,后来是补过的,但补漏了一批——具体漏的原因没人说得清了,交接了好几手。结果就是现在有一批记录,expire_at 早就过去了,status 还挂着 ACTIVE。产品要一份准确名单,给这批人发到期提醒。上周五下午给我的,说下周三之前要。

按我原来的想法,这活我自己写,大概一天。SQL 加个 python 包一层,分批跑,加日志,加幂等(重复跑不能重复更新,这个是底线),跑之前先出个 dry-run 看看影响行数。我本来想自己写,毕竟——其实也不是不能写,就是——算了,就是想省点时间。

所以我把建表语句、五条样本数据、还有产品给的口径原话贴给 AI 了,让它先出一版。

它出得比我预想的快,也比我想的细。有几个地方是我没考虑到的:

一个是基准时间。我本来打算直接在 SQL 里用 now(),这样批次之间跨秒了,基准时间就飘了,第一批按 10:00:01 判、第二批按 10:00:03 判,理论上会漏掉夹在中间那一两秒的记录。它是在脚本启动的时候取一次 datetime.now(),存成变量往下传。这个我确实没想到,之前写类似脚本我也没这么做过(不知道算不算我水平不够,可能算)。

第二个是 --dry-run 默认开着,要显式加 --apply 才真动数据。这个纯属我没想到,但是很合我的习惯。

第三个是它 WHERE 里带了 status IS NULL。我原本以为那批历史数据状态都是 ACTIVE,NULL 我还真没查过。

看到这你可能以为我要夸它了。没有,它差点让我栽。

按我做测试的习惯,上线之前我先造了三条数据:expire_at 正好等于基准时间的、早一秒的、晚一秒的。跑 dry-run,对不上。少了几十条。

查了一下,它用的是 <,不是 <=。业务口径是"到期时间早于或等于当前时间就算过期"。差一个等号。关键是那批历史数据里,因为当年定时任务是整点整分跑的,expire_at 卡在整秒上的特别多。这一秒漏掉的就是一大片,而且是静默漏,不报错。

然后我又顺手查了下 status 的分布,发现还有一批是空字符串 '',不是 NULL,也不是 ACTIVE。它那条 IS NULL 兜住了一半,空字符串漏了,dry-run 的行数跟实际 count 差了四百多条。

第二个问题算我运气好,是查 count 查出来的,不是设计出来的。这里我可能想复杂了,但我觉得如果那天我没顺手 count 一下,这脚本就这么跑上去了,跑完零报错,谁也不知道漏了四百条。

改了两个地方,我又把 dry-run 跑了一遍,三条边界数据都进去了,行数跟 count 对上了。真跑,两批,跑完又原样重跑一次验证幂等,行数没变。

零事故。实际写脚本的时间大概二十分钟,我过用例加验证花了一下午。同事说这活干得快,我没反驳也没接话。

先这样吧。那个 dry-run 默认开的写法我留下来了,以后写这类脚本当模板用,后面还有两个类似的回补,等我整理完再说。

敏姐转开发
敏姐转开发

测试八年,转开发第一年。慢一点没关系,返工最贵。

查看主页 →