晚上九点四十,日志还在刷。deleted: uploads/2024/03/... 一行一行往下滚,我盯着屏幕,手里的可乐已经温了,忘了喝。
事情得从上周说。产品在群里甩了张截图,OSS 账单比上个月涨了小一半,问能不能清一下没用的图。这活落到我头上,因为公司就俩前端,另一个在休假。我对 OSS 的了解约等于零,只知道图片传上去会给你个链接。
那就啃文档。阿里云这个 node sdk 的文档,中文版有一半的接口没写,只能翻英文的。查了下 listObjects,有个 prefix 参数,大概就是前缀匹配的意思,按目录去列。我要做的是:把数据库里所有在用的图片 key 导出来,跟桶里列出来的做差,差集就是孤儿,删掉。
这逻辑简单得像小学题。我写了大概八十行。
删之前我想着得先预览一下,就加了个开关,环境变量控制,if (process.env.DRY_RUN) 就只打印不删。启动的时候 DRY_RUN=1 node clean.js。想得挺好。
跑起来第一遍,日志哗哗刷 deleted。我愣了两秒——我说的是预览啊。然后我看见脚本里那行,我写的是 process.env.DRRY_RUN。多打了一个 R。启动命令里没有 DRRY_RUN 这个变量,它是 undefined,走 else,真删。
现在我打字的时候手还是有点抖。当时我第一反应是按 Ctrl+C,但已经跑了十几秒了。第二反应是把进程 kill 掉,第三反应才想起来该去看看删了多少。
三百一十二个。我盯着那个数字,脑子里一片白。我们组的图库是运营攒了两年的素材,活动页、商品图、老板年会合影都在里面。真删了,我下个月工资可能就没了。
给组长发消息,他回了四个字:先别动。过了三分钟又发一条:看看有没有开版本控制。
这个我倒是知道,翻文档的时候扫到过一眼。进控制台一看,开了,去年开的,好像是因为之前有人手滑删过一次东西,老板让人开上的。那一瞬间我想给去年那个手滑的人磕一个。
但是开了版本控制不等于能一键恢复。OSS 的做法是:删掉一个对象,其实是给它加了个删除标记(delete marker?),旧版本还在,得挨个捞。文档里 listObjectVersions 返回一个列表,每个 key 有好几个 versionId,时间倒序,第一个基本上就是那个删除标记,得往后挑。
我写了个恢复脚本,先用几个文件试。试了半小时全是 404,报错是 NoSuchKey。我以为是权限问题,查了半天 RAM 角色,又去问 AI,AI 说是没权限,我照着它说的加了一堆策略,还是 404。
后来我把报错原文一字一字抠出来看,里面那串 key 是被转义过的,%E4%B8%AD%E6%96%87 这种。我才反应过来,我们那批图里有一半文件名是中文的,还有空格和括号。copyObject 的 source 得先 encodeURIComponet(拼错了,是 Component,当时查了两遍才拼对)。加上之后,通了。
十点二十恢复完,第三百一十二个文件落地。我把数据库导出的那张表又跑了一遍对比,数量对上。没多也没少。
中间还有个插曲,前一个小时恢复出来的文件全是 0 字节,我以为是源文件坏了,心跳都停了半拍。后来发现我 copy 的时候没指定 versionId,它默认复制最新版本——也就是那个删除标记,复制出来当然什么都没有。
第二天产品问我图库清得怎么样了,我说清完了。没说别的。那个脚本我留着,把那行改成 DRY_RUN,后面又加了一句 if (process.env.DRRY_RUN) { throw new Error('拼错了'); }。算是给自己留个碑。
今日单词:versioning,版本控制。第五次查它了,之前一直记成 versoning。