我使用的是最新版本的 Homestead。 我还设置了 Laravel Horizon。 我使用 Redis 作为队列驱动程序。 Laravel 是 5.6 版,是全新安装的。
发生的事情是我的作业都失败了(即使作业正确退出)。
我使用自定义命令通过命令行运行作业:
vagrant@homestead:~/myapp$ artisan crawl:start
vagrant@homestead:~/myapp$ <-- No CLI errors after running
app/Console/Command/crawl.php
<?php
namespace MyApp\Console\Commands;
use Illuminate\Console\Command;
use MyApp\Jobs\Crawl;
class crawl extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'crawl:start';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Start long running job.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
Crawl::dispatch();
}
}
app/Jobs/Crawl.php
<?php
namespace MyApp\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class Crawl implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The number of seconds the job can run before timing out.
*
* @var int
*/
public $timeout = 3600;
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 1;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$crawl = new Crawl();
$crawl->start();
}
}
应用程序/Crawl.php
<?php
namespace MyApp;
class Crawl
{
public function start()
{
ini_set('memory_limit','256M');
set_time_limit(3600);
echo "Started.";
sleep(30);
echo "Exited.";
exit();
}
}
worker.log
[2018-03-21 10:14:27][1] Processing: MyApp\Jobs\Crawl
Started.
Exited.
[2018-03-21 10:15:59][1] Processing: MyApp\Jobs\Crawl
[2018-03-21 10:15:59][1] Failed: MyApp\Jobs\Crawl
来自 Horizon 失败的作业详情
Failed At 18-03-21 10:15:59
Error Illuminate\Queue\MaxAttemptsExceededException:
MyApp\Jobs\Crawl has been attempted too many
times or run too long. The job may have previously
timed out. in /home/vagrant/app/vendor/laravel
/framework/src/Illuminate/Queue/Worker.php:396
laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/vagrant/myapp/artisan queue:work --sleep=3 --tries=1 --timeout=3600
autostart=true
autorestart=true
user=vagrant
numprocs=1
redirect_stderr=true
stdout_logfile=/home/vagrant/myapp/worker.log
配置/queue.php
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'retry_after' => 90,
'block_for' => null,
],
.环境
QUEUE_DRIVER=redis
概要
查看我的 worker.log
我可以看到我的类(class)的输出有效:
Started.
Exited.
但是作业被报告为失败。为什么?
奇怪的是,同样在 worker.log
中,它为一项工作说了两次 Processing
:
[2018-03-21 10:15:59][1] Processing: MyApp\Jobs\Crawl
[2018-03-21 10:15:59][1] Failed: MyApp\Jobs\Crawl
非常感谢任何帮助!
更新
删除 exit()
已解决问题 - 这很奇怪,因为 PHP 手册说您可以使用 exit()
“正常”退出程序:
<?php
//exit program normally
exit;
exit();
exit(0);
最佳答案
Removing the
exit()
has resolved the issue - this is strange as the PHP manual says that you can useexit()
to exit the program "normally"
这对于常规程序来说是正确的,但是 Laravel 中的排队作业不遵循相同的生命周期。
当队列系统处理一个作业时,该作业在现有的队列工作进程中执行。具体来说,queue worker 从后端获取作业数据,然后调用作业的 handle()
方法。当该方法返回时,队列 worker 运行一些代码来完成作业。
如果我们退出一个作业——通过调用exit()
、die()
,或者通过触发一个 fatal error ——PHP 停止运行该作业的工作进程好吧,所以队列系统永远不会结束作业生命周期,作业也永远不会被标记为“完成”。
我们不需要明确退出作业。如果我们想早点完成工作,我们可以简单地从 handle()
方法返回:
public function handle()
{
// ...some code...
if ($exitEarly) {
return;
}
// ...more code...
}
Laravel 还包含一个特征,InteractsWithQueue
,它提供了一个 API,使作业能够 self 管理。在这种情况下,我们可以从具有此特征的作业中调用 delete()
方法:
public function handle()
{
if ($exitEarly) {
$this->delete();
}
}
But the job is reported as failed. Why? Strangely, also in the worker.log, it says Processing twice for one job
如上所述,作业无法成功完成,因为我们调用了 exit()
,因此队列系统尽职尽责地尝试重试该作业。
关于php - Laravel - 作业报告失败(即使它正确退出),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49404153/