【问题标题】:Laravel - Job reporting as failed (even though it exits correctly)Laravel - 作业报告失败(即使它正确退出)
【发布时间】:2018-08-30 10:39:48
【问题描述】:

我正在使用最新版本的 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();


    }
}

app/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

config/queue.php

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => 'default',
    'retry_after' => 90,
    'block_for' => null,
],

.env

QUEUE_DRIVER=redis

概要

看看我的worker.log,我可以看到我的课程的输出有效:

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);

【问题讨论】:

    标签: php laravel queue laravel-horizon


    【解决方案1】:

    删除exit() 已解决问题 - 这很奇怪,因为 PHP 手册说您可以使用 exit()“正常”退出程序

    这对于常规程序来说是正确的,但是 Laravel 中的排队作业不遵循相同的生命周期。

    当队列系统处理作业时,该作业在现有队列工作进程中执行。具体来说,队列工作者从后端获取作业数据,然后调用作业的handle() 方法。当该方法返回时,队列工作者会运行一些代码来完成作业。

    如果我们退出作业——通过调用exit()die() 或触发致命错误——PHP 也会停止运行该作业的工作进程,因此队列系统永远不会完成作业生命周期,并且作业永远不会被标记为“完成”。

    我们不需要明确退出工作。如果我们想早点完成工作,我们可以简单地从handle()方法返回:

    public function handle() 
    {
        // ...some code...
    
        if ($exitEarly) {
            return;
        }
    
        // ...more code...
    }
    

    Laravel 还包含一个 trait,InteractsWithQueue,它提供了一个 API,使作业能够自我管理。在这种情况下,我们可以从具有此特征的作业中调用 delete() 方法:

    public function handle()
    {
        if ($exitEarly) {
            $this->delete();
        }
    }
    

    但是作业被报告为失败。为什么?奇怪的是,在 worker.log 中,它说为一项工作处理两次

    如上所述,作业无法成功完成,因为我们调用了exit(),因此队列系统尽职尽责地尝试重试作业。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-04
      • 1970-01-01
      • 2013-12-01
      • 2021-02-03
      • 1970-01-01
      相关资源
      最近更新 更多