WangMao's Blog
原 Secret Blog,坐标深圳,码农

Laravel 队列未重启进程引发的「Bug」

TOC

  1. 起因
  2. 调试
  3. 解决

起因

周五在公司加班的时候,调试了一个用户验证短信的一个 Bug,为了尽量做到接口的调用限制,对发送过的手机号设置了一定时长的「黑名单」机制,原理是将发送过的手机号存入缓存中,发送短信的时候获取缓存是否存在,如果存在就说明超频发送了。说实话很简单的一个功能,我却破天荒的调试了半天没搞明白。

后来,老大就坐在旁边,我俩一起调,从生成验证码到发送日志,全给丢到 debug 日志,挂着 tail 命令监听。

然鹅!模拟用户注册居然没有打印验证码日志,只有发送日志!

没记录日志,还始终报验证码错误,真是莫名其妙。

调试

首先,我将视线转移到缓存时间上,发现缓存时间只有 1 分钟,也就是说如果用户填写资料比较慢的话,验证码很可能就过期了!调试嘛,改到 10 分钟先。提交后更新生产环境代码。还是报错!

emmm…难道缓存系统出问题了?还是说 Redis 写不进去了?发送完验证码后,使用 Laravelartisan tinker 打印缓存,居然不是验证码,是手机号!诶,我这儿不是改了吗?(没错,刚开始的时候我勿将手机号存到 values 去了)。代码里加日志,想打印下看下什么情况。可是新加的打印日志死活打印不出来。

不行了,我要冷静下,慢慢的开始分析修改前和修改后的逻辑。

修改前:用户传入手机号->系统生成验证码(这里验证码是手机号)->将发送任务丢到队列->用户收到短信后填写->后端校验。

修改后:用户传入手机号->系统生成验证码(这里新加了日志输出)->将发送任务丢到队列->用户收到短信后填写->后端校验。

而现在的问题是:系统生成的验证码还是手机号,尽管我已经修改了;调试日志不打印!

也就是说。。队列没更新!

解决

分析出队列没更新,我立马就去查了 supervisor 的文档。之前更新队列都只使用了 rereadupdate 命令,只是更新了配置文件,但是队列并没有重新启!而 Laravel 的文档 队列 中提到:

注意一旦 queue:work 命令开始执行,它会一直运行直到它被手动停止或终端被关闭。

supervisor 是不会被关闭的,何况我给了 4 个子进程。而文档中又提到:

记住,队列处理器是一个常驻的进程并且在内存中保存着已经启动的应用状态。因此,它们并不会在启动后注意到你代码的更改。所以,在你的重新部署过程中,请记得 重启你的队列处理器.

也就是说,队列还是保持第一次执行的状态。难怪缓存值修改了没用,日志打印不出来也是这个原因。

重启 supervisor 队列命令:

1
supervisorctl restart laravel-queue

问题得到解决,真是被自己写的 Bug 蠢哭了。