我有一个应用程序运行许多不同类型的作业,这些作业运行几秒钟到一小时。这需要我有两个独立的队列连接,因为在绑定到连接而不是队列后重试(尽管它们都使用Redis,这很烦人,但现在不是问题所在(。一个连接的重试时间为600秒,另一个为3600秒(或一小时(。我的工作实现了ShouldQueue
并使用了特征Queueable, SerializesModels, Dispatchable, InteractsWithQueue
。
现在来解决问题。我创建了一个TestJob
,它可以睡眠900秒,以确保我们通过retry_after限制。当我尝试使用以下方法在特定连接上分派作业时:dispatch(new Somejob)->onConnection('redis-long-run')
或者就像我以前在作业的构造函数中所做的那样(过去总是有效的(:
public function __construct() {
$this->onConnection('redis-long-run');
}
该作业由队列工作程序获取,它运行600秒,然后工作程序重新启动作业,注意到它已经运行过一次,并使其失败。300秒后,该作业成功处理。如果我的工作人员允许多次尝试,重复的作业将并行运行300秒。
在我的测试工作中,我还打印出$this->connection
,它确实显示了正在使用的正确连接,所以我猜广播公司只是完全忽略了它。
我在Docker环境中使用Laravel 5.8.35和PHP 7.3。主管负责管理我的员工。
编辑:我已经确认升级到Laravel v6.5.1 后行为仍然存在
复制步骤:
- 将队列驱动程序设置为Redis
- 在queue.php中创建两个不同的Redis连接,一个名为
redis
,retry_after为600,另一个名redis-long-run
,retry_after为3600。在我的情况下,它们也有不同的队列,尽管我不确定这是否是这个测试所必需的
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 600,
'block_for' => null,
],
'redis-long-run' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'long_run',
'retry_after' => 3600,
'block_for' => null,
]
]
- 创建一个小命令来调度我们的测试作业三次
<?php
namespace AppConsoleCommands;
use AppJobsTestFifteen;
use IlluminateConsoleCommand;
class TestCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test:fifteen';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
for ($i = 1; $i <= 3; $i++) {
dispatch(new TestFifteen($i))->onConnection('redis-long-run');
}
}
}
- 创建测试作业
<?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationEventsDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use function sleep;
use function var_dump;
class TestFifteen implements ShouldQueue
{
use Queueable, SerializesModels, Dispatchable, InteractsWithQueue;
private $testNumber;
public function __construct($testNumber)
{
$this->onConnection('redis-long-run');
$this->testNumber = $testNumber;
}
public function handle()
{
var_dump("Started test job {$this->testNumber} on connection {$this->connection}");
sleep(900);
var_dump("Finished test job {$this->testNumber} on connection {$this->connection}");
}
}
- 运行队列工作者。我为这些工人使用带有以下配置的supervisor
[program:laravel-queue-default]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/artisan queue:work redis --queue=default --tries=3 --timeout=600
numprocs=8
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:laravel-queue-long-run]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/artisan queue:work redis --queue=long_run --tries=1 --timeout=3540
numprocs=8
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
- 执行手工命令
php artisan test:fifteen
那么我是做错了什么,还是应用的连接真的没有得到尊重?
此外,不能仅根据每个作业或队列来决定retry_after应该是什么,从而能够使用REDIS
作为我的实际队列驱动程序,这背后的设计理念是什么?为什么我不能选择Redis作为队列处理程序,并决定queue-1在60秒后重试,queue-2在120秒后重试?当他们使用完全相同的Redis实例和所有东西时,不得不为此设置两个连接,我觉得很不自然。
不管怎样,这里希望一些人能在这个问题上发光发热。提前谢谢。
根据我的理解,您的连接始终是redis
,因此您应该在调度时指定队列:
dispatch(new TestFifteen($i))->onQueue('long_run');
连接是不同的驱动程序,如redi、sync、AWS等。您的队列与该连接是不同的配置或多个作业堆栈。