单片机技术网|技术阅读
登录|注册

您现在的位置是:单片机技术网 > 技术阅读 > 应届生刚进公司就让公司损失了100万是什么体验?

应届生刚进公司就让公司损失了100万是什么体验?

大家好,我是正在面向监狱编程的 陌溪

最近几天没有怎么在群里冒泡和公众号发文,是因为陌溪在公司摊上大事了。我负责的一个模块在前几天凌晨上线后,出现事故直接导致发生了 100W 的退款,群里热心小伙伴纷纷对我表示关心。。

来自热心小伙伴的关心

不过这里也需要澄清一下,陌溪还没有被带走,这阵子也还在公司正常的在搬砖。。

因为字节对于事故的处理,推崇的是 非指责文化。也就是说程序员不用担心在制造事故后,而被指责或者得到处分,同时也不会因为出现事故而导致今年的绩效就无了。公司更多的是要求我们在事故中能够及时复盘,能够做到以下的几点:

  • 找出事故的影响范围大小

  • 什么原因而导致事故发生

  • 如何避免这类事故以后再次发生。

也正因为字节的 非指责文化 ,能够在很大程度上避免同时在遇到事故时互相甩锅,从而能够快速的定位到问题,然后通过复盘找到最根本的原因。同时通过组织复盘会议,也能让大家从事故中都能学习到,避免其它同学再次踩坑。

事故的起因

为了方便小伙伴理解这次事故是怎么发生的,陌溪这里就举一个游戏账号代练的场景来聊聊。

首先,假设陌溪目前开发了一个游戏账号代练平台。嗯。。姑且就只代练 王者荣耀 吧。【当然,游戏代练官方可是不允许的哟,小伙伴可不要铤而走险,导致游戏账号被封了】

然后,陌溪提供游戏代练服务,从青铜代练到王者只需要 100 块,用户通过陌溪做的 王者荣耀 代练平台进行下单。

下单后,这里就会创建一个订单,这里的订单涉及到几个状态,订单创建,订单支付,订单服务中,完成代练, 订单完成。

用户在平台下单,首先当然需要填写一些信息,比如目前的王者等级信息,然后王者荣耀的英雄等等。然后点击提交表单,提交后,就会跳转到一个支付页面,同时在支付页面也会有一个支付截止时间,我们在这个截止时间内完成支付,订单状态就会进入到订单支付的状态,这个截止时间字段,对应数据表就用 endTime 表示,然后 endTime = createTime + 30 min 。

支付截止时间

这个时候,平台就会把订单分发给账号代练人员,如果有选手接单的话,那么订单状态就会从 订单支付 状态,变成 订单服务中。最后选手完成王者的代练后,就会提交到游戏信息到平台上,然后订单状态就会变成 完成代练。用户进行验收,验收通过后,就把钱打给选手,最后完成了订单。

上面提到的其实是一个正常的流程,最近陌溪需要添加一个新的功能,就是能够支持自动退款的操作。要求如果处于服务中的订单,要是选手 30 天没有提交代练完成的信息,那么就会给用户自动退款。这个时候,就可以继续复用上面提到的 endTime,只需要设置一下endTime = endTime + 30 Day 。

通过写一个定时器,每隔几分钟查询订单表,判断是否有处于服务中的订单,并且 endTime 小于当前时间的,如果查询到了的话,就说明这个订单已经超过 30 天的服务周期,那么就执行退款流程。

这个流程上其实是没有问题的,出问题的是在一些历史的订单,因为对于一些历史处于服务中的订单,它的endTime 还是支付截止时间,而不是服务截止时间,即 endTime = createTime + 30 min。

所以在自动退款功能上线后,会把历史服务中的订单也扫描出来,然后执行退款操作,但是此时退款操作并没有完成,而是失败了,因为陌溪写的部分逻辑对旧订单没有适配,从而触发了陌溪写的兜底的错误报警,造成所有退款操作都被回滚了。

这时,大佬拉下代码,帮我解决了一下这个兜底错误报警,然后很快退款流程顺利执行。最后在发现问题的时候,已经造成了 100W 的损失,陌溪感觉自己马上就要被带走了。。

事故复盘

出事故后,首先肯定不要慌,第一时间先定位到异常代码,然后进行解决。其实通过上述的描述,我们也可以发现根本的问题,即对于一些历史订单处理上出现问题,这个时候,需要做的就是通过对数据库进行刷数操作,把历史订单的 endTime 增加 30 天,比如执行这样一个SQL语句:

UPDATE order SET end_time = DATE_ADD(create_time, INTERVAL 30 DAY)  WHERE STATUS="服务中"

其中,这里用到了,MySQL 的一个内置函数 DATE_ADD,可以向日期添加指定的时间间隔。

语法格式如下:DATE_ADD( date, INTERVAL expr type) ,其中 date 参数是合法的日期表达式。expr 参数是您希望添加的时间间隔,type 表示时间单位,比较常见的单位

  • SECOND:秒

  • MINUTE:分钟

  • HOUR:小时

  • DAY:天数

  • MONTH:月份

  • YEAR:年

同时在进行订单状态的变更时,如果该状态不需要使用到 end_time 时,那么需要及时将其清空,而不能让其存储在数据库中,这样也可以避免以后可能再次发生。

order.endTime = NULL;
order.updateById();

最后就是,在修复 BUG 的时候,尤其是涉及到金额类退款操作的时候,需要提高警惕意识。要明确为什么会出现这个 BUG,修复这个 BUG 后会发现什么问题。

这次事故的发生,陌溪也是主要责任人,毕竟这部分逻辑是我实现的,毕竟没有认真观察到之前 end_time 埋下的祸根,同时在修复 BUG 的时候比较仓促上线,最终酿成后果。

不过幸运的是,最后我们的业务和产品同学非常给力,将损失降低到了几万块,并且还在持续的跟进和追回~

感谢业务和产品同学

好啦,本期的事故复盘就到这里啦,希望以后小伙伴们在搬砖过程中,能够仔细把控每个环节,不要和陌溪一样,造成事故而翻车了。

我是陌溪,我们下次再见~

往期推荐

结语

应各位小伙伴们的需求,陌溪已经把 大厂校招笔记 已经整理成 PDF 版本啦,方便大家在手机或者电脑上阅读。如果有需要离线阅读的小伙伴可以到公众号回复 PDF。