我有一个应用程序运行许多不同类型的作业,这些作业运行几秒钟到一个小时。这需要我有两个单独的队列连接,因为 retry_after 绑定到连接而不是队列(即使它们都使用 Redis,这很烦人,但现在不是问题)。一个连接的 retry_after 为 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,
]
]
- 创建一个小命令来分派我们的测试作业 3 次
<?php
namespace App\Console\Commands;
use App\Jobs\TestFifteen;
use Illuminate\Console\Command;
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 App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
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}");
}
}
- 运行你的队列工作者。我为这些工作人员使用具有以下配置的主管。
[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 实例和所有东西时,我觉得为此设置两个连接是很不自然的。
无论如何,这里希望有人能对这个问题有所了解。先感谢您。