php - Laravel - 作业报告失败(即使它正确退出)

标签 php laravel queue laravel-queue laravel-horizon

我使用的是最新版本的 Homestead。 我还设置了 Laravel Horizo​​n。 我使用 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

来自 Horizo​​n 失败的作业详情

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() “正常”退出程序:

https://secure.php.net/manual/en/function.exit.php
<?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 use exit() 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/

相关文章:

php - 使用 php 和 javascript 进行 minecraft 用户检测

php - 使用 Laravel 服务提供者覆盖连接器类

javascript - 从 vue-router 的链接获取 'id' 值

c++ - 将队列转换为堆栈?

c++ - 如何获取 vector 队列的前端或顶部元素?

php - 加入两个 mysql 查询?

php - 如何获取每个类别中具有特定百分比的数据

php - 检索 id 而不显示它

Laravel ER 图生成器 getAllModelsFromEachDirectory()

使用堆栈和队列的 C++ 计算器