Laravel队列工作原理及5.5版本Redis队列测试问题求助
Laravel队列常见问题解答
1. Laravel队列任务的工作机制是怎样的?
咱们可以把Laravel队列理解成一个“后台任务调度员”,核心作用就是把耗时的操作从用户的请求流程里抽出来,让系统在后台慢慢处理,这样用户不用傻等就能拿到响应。具体的工作流程大概分这几步:
- 任务投递:当你调用
Job::dispatch($data)或者dispatch(new MyJob($data))时,Laravel会把你的任务类序列化(变成能存进队列驱动的格式),然后根据config/queue.php里的配置,把这个任务推送到指定的队列里——比如你配置的Redis驱动,就会把任务存到Redis对应的列表中,每个队列对应一个独立的列表。 - 任务存储:队列驱动(Redis、数据库、Beanstalkd这些)会把任务暂时存起来,等待Worker来取。Redis的话就是用列表结构来维护任务的顺序,先进先出(当然你也可以通过队列优先级调整顺序)。
- Worker消费任务:你得手动启动队列Worker进程——用
php artisan queue:work或者queue:listen命令。Worker会一直盯着你指定的队列,一旦发现有任务,就把它取出来反序列化,然后执行任务类里的handle()方法。这里要提一句,queue:work是常驻进程,效率更高;queue:listen每次轮询都会重新加载框架,适合开发调试用。 - 任务收尾:如果任务执行成功,Worker就会把它从队列里删掉;要是失败了,会按照你在任务类里定义的重试次数自动重试,超过次数后就会被移到失败队列,你可以用
php artisan queue:failed查看这些失败任务,还能通过queue:retry重新执行。
2. Laravel 5.5 Redis队列测试环境默认队列不生效的问题
这个坑我之前也踩过!核心原因是Laravel在测试环境下,为了避免误操作生产队列,默认会对队列做一些“特殊处理”,导致你在queue.php里配置的默认队列没被读取到。具体可以从这几个方向排查:
- phpunit.xml的环境变量覆盖:打开项目根目录的
phpunit.xml,看看<php>标签里是不是设置了QUEUE_DRIVER为sync,或者有没有QUEUE_DEFAULT的环境变量把你在queue.php里的配置覆盖了。比如如果有<env name="QUEUE_DRIVER" value="sync"/>,那测试时队列会同步执行,而且默认队列的配置会被忽略。 - Fake队列的默认行为:如果你在测试用例里用了
Queue::fake()来模拟队列(这是Laravel测试队列的常用方式),Fake队列默认不会读取queue.php里的默认队列名,而是会把任务放到一个内部的“fake”队列里。这时候你要么显式用->onQueue('tickets')指定队列,要么在测试前手动设置默认队列:// 在测试方法或者setUp方法里设置 config(['queue.default' => 'tickets']); - 测试环境的配置文件覆盖:检查一下有没有
config/testing/queue.php这个文件——Laravel允许不同环境有独立的配置文件,如果这个文件里把default改成了其他值,那测试时就会用这个配置,而不是config/queue.php里的。
解决办法也很清晰:
- 如果你需要在测试中用真实的Redis队列(而不是sync或Fake),可以在
phpunit.xml里修改环境变量:<env name="QUEUE_DRIVER" value="redis"/> <env name="QUEUE_DEFAULT" value="tickets"/> - 如果用
Queue::fake(),要么在测试前设置默认队列,要么在断言的时候指定队列:config(['queue.default' => 'tickets']); Job::dispatch($payload); // 断言任务被推送到了tickets队列 Queue::assertPushedOn('tickets', Job::class);
内容的提问来源于stack exchange,提问作者laketuna
相关产品推荐
相关产品推荐

