勿删

出事那天是周四,凌晨两点。

告警响的时候我刚睡着,手机在枕头边上震。我摸过来一看,是订单服务的超时。不是全挂,是慢,慢到一批请求卡在七秒以上,然后被网关掐掉。

我起来开电脑。媳妇翻了个身,没醒。

日志拉下来,二十多万行,我 grep 了半天,最后锁在下游一个用户画像服务上。那边超时设的十秒,卡了七秒。是老李他们组的东西。

问题不在我们这边。

按说我该把链接甩到群里,让老李他们看,然后关电脑睡觉。我大概是甩了。

但我没关电脑。因为我在翻调用栈的时候,撞见了那一行。

校验函数不长,二十来行。中间有一行:

ini 复制代码
if (userId == 10086L) {
    return true;
}

我盯着这行看了很久。

10086。一个写死的用户 ID。硬编码。判断命中就直接返回 true,跳过后面所有的校验。

这行上面什么注释都没有。

第二天上午,老周端着杯子过来,看我屏幕。

他说,你还在看这个。

我说,嗯。

他说,那行我知道。

我抬头看他。

他说,我十年前就见过。那时候我跟你在一个组,我问过你,你说先这样,明天改。

我说,我说过吗。

他说,你说过。

老周下个月走。不是被裁,是他自己要回合肥,老婆那边开了个店,他过去管。他比我还大两岁。他端着杯子站了一会儿,说,我劝你也想想。

我说,我想什么。

他说,随便想想。

他就端着杯子走了。

我打开终端,git blame。

php 复制代码
a3f9c21e  (陈默  2016-03-17 14:40:52)

陈默。我的名字。

2016 年 3 月 17 日,下午两点四十。十年前。

commit message 只有一个词。

matlab 复制代码
fix

就一个 fix。没有别的话。没写为什么,没写改了什么,没写关联哪个工单。十年了,我给那天下午留的全部线索,是一个 fix。

我那年二十六岁。

2016 年那会儿公司在西二旗,租了半层,工位挤得像网吧。空调一到下午就不管用,靠窗那排晒得键盘发烫。我坐倒数第二排,旁边是个测试,姓李,天天中午带饭,饭盒一打开整排都能闻见。

那阵子在赶一个版本,连着加了三周的班。产品每周三改一次需求,改完开发重排。那个版本要做用户分级,VIP 用户走一套宽松的校验。

那块逻辑不是我写的。是外包做的,做完人就撤了。留下一份文档,一共两页,第二页是空白的。

我不敢动。

现在想想,那时候我连读都不太读得懂。整个下午我都在加日志,加完部署,看输出,再改,再部署。那时候部署一次要十五分钟,一天也就改那么几十次。

上线第二天就出事了。有个用户进不去。

客服转过来的工单我大概记得,说一个老用户,付不了款,一直转圈。

我查了一下午没查出来。到第二天下午,我实在没办法了,就在那个校验函数里加了一行,把这人的 ID 写进去,跳过去。

当时我心里想的是,先这样,让这个用户能用,明天再说。

明天。

十年里我大概说过三百次明天。

小陈是去年来的,坐我斜对面。午饭回来他路过,看我开着那个文件。

他说,默哥,这行干嘛的。

我说,不知道。

他笑了一下,以为我谦虚。他说,是特殊用户吧。

我说,可能是。

他说,能删吗。

我说,不知道。

他愣了一下,说,哦,就走了。

我把仓库整个拉下来,想找找当年的分支或者 tag。没有。2018 年我们换过一次 git 服务,从自建的 GitLab 迁到现在的平台,历史是导过来的,分支丢了一部分,只留了 master。2016 年那些分支全没了。

我又去查工单。

工单系统十年里换过三次。2016 年用的是最早那个,自研的,叫什么我都忘了。后来的都上云了,最新的这个连界面都不一样。

我给 IT 发消息,问 16 年的工单还能查吗。

IT 是个小姑娘,隔了两天回我,说找到了,在老的 NAS 上,那个 NAS 明年要报废,问我要不要导出一份。

我说要。

她导出给我,一个 Excel,三万多行,2016 年的在里面,大概四千条。

我搜 10086。没有。

我搜"付款""转圈""无法下单"。出来几十条,我一条条看,看到第三十七条的时候,看见了。

标题是「老用户无法下单,急」。

提交时间 2016 年 3 月 16 日 19:22。提交人:客服-王静。处理人:陈默。状态:已解决。

解决时间:2016 年 3 月 17 日 14:38。

我看着这个时间。14:38。代码提交是 14:40。

中间隔了两分钟。那两分钟我大概点了杯水,或者上了个厕所。

再往下看工单内容。用户手机号中间四位是星号,我看不全。备注里写着:用户 60 岁,女儿帮着注册的,说用了几个月一直好好的,昨天开始就不行了。

最后一条回复是我写的,只有一句:「已修复,请用户重试。」

我打开数据库。

这种生产库我进不去,要走审批,我提了个只读的临时权限,等了一天半。批下来那天是周一。

sql 复制代码
select id, nick_name, reg_time, last_login_time
from user where id = 10086;

查出来了。

makefile 复制代码
id       : 10086
nick_name: 138****6027
reg_time : 2015-11-03 09:14
last_login: 2017-08-12 11:26

2015 年 11 月注册。2017 年 8 月 12 号最后一次登录。

我又查了他的订单。

makefile 复制代码
order_count: 3
first_order: 2015-11-03
last_order : 2016-03-18

2016 年 3 月 18 号。就是我加那行的第二天。

他下完那一单,就没再下过。

中间隔了大概一年半,2017 年 8 月他登录过一次,然后就再没有了。

也就是说,那行为他跑了一年半。

为他之外的人,它跑了十年。那十年里它一次都没生效过,因为再没有第二个人是 10086。它就那么待着,每来一个请求就问一句,是你吗,不是,是你吗,不是。

问他的人早就不来了。他还在问。

我在工位上坐了很久。屏幕上是那个 2017 年 8 月的时间戳。那是个夏天,数据库里那天的记录只有一条,他在 11 点 26 分登录,待了多久不知道,日志不记这个。

我忽然想,他那天上来干什么。看了看就走了,还是想买什么没买成。

这个我永远查不到。

那天回家我吃得挺早。闺女在上初中,吃饭的时候问我,爸爸你在干嘛最近。

我说,修 bug。

她说,修好了吗。

我说,还没有。

她说,那你明天再修。

我说,行。

她低头扒饭。

我把这个故事的结局想了好几种。

一种是我把那行删了。删了之后跑了两天压测,没出问题,就上线了。那十年里没人再提起 10086。

一种是我把它抽出去,做成配置,放到用户白名单表里。工单里留一句「历史遗留,2016 年处理」,然后关掉。

第三种是我什么都没做。

最后我做的,跟这三种都不一样。

周四下午,我提交了一行。

kotlin 复制代码
// 10086 勿删 原因见工单 OPS-2016-0417
if (userId == 10086L) {
    return true;
}

改完我盯着那个工单号看了一会儿。

那个号是我编的。

我不记得了。十年的工单,我记不清是 0417 还是 0174,还是别的什么。我只知道如果什么都不写,下一个看到这行的人,会直接删掉。

写一个错的,至少能让他停一下。

他停下来,去查这个单号,查不到,然后他会多想一会儿。多想的那一会儿,就是我留给 10086 的全部东西。

提交完我关电脑,看了眼窗外。西二旗那边的楼早拆了,现在这片也快拆了,明年我们搬通州。

我收拾包的时候想,明年搬过去,那个 NAS 就报废了。

那个 Excel 我存了一份在自己的硬盘上。

相关推荐
IT_陈寒4 小时前
用了Proxy才发现以前的JavaScript白写了
前端·人工智能·后端
唐青枫4 小时前
别把 ArrayList 当成会自动管理内存的 List:Zig 动态数组从入门到实战
后端
鸿蒙开发5 小时前
我为 HarmonyOS 做了一个统一大模型 SDK:@hmkit/ai 正式开源
后端
猪是念来过倒5 小时前
Semaphore 与 RateLimiter:并发控制双雄详解
后端
掘金者阿豪5 小时前
异构数据同步最怕什么?不是同步慢,而是数据对不上
后端
程序员cxuan6 小时前
Claude 官方的学习教程,太强了。
人工智能·后端·程序员
老孙讲技术6 小时前
把工地遮挡和掉线接进项目部:setMessageCallback 订 alarm 与 deviceStatus
后端·物联网·音视频开发
老孙讲技术6 小时前
关店后有人进门,监控值班群却没响:用 setMessageCallback 订 human,再用 aiHuman 打开人形
后端·物联网·音视频开发
LEE6 小时前
原来 Claude Code 最厉害的工具,一行代码都不写
前端·后端