Laravel - Отчет о задании как сбой (даже если он корректно завершается)

Я использую последнюю версию Homestead. У меня также есть Laravel Horizon. Я использую Redis в качестве драйвера очереди. Laravel является версией 5.6 и является новой установкой.

То, что происходит, - мои рабочие места терпят неудачу (даже если работа завершается правильно).

Я запускаю работу через командную строку с помощью пользовательской команды:

vagrant@homestead:~/myapp$ artisan crawl:start
vagrant@homestead:~/myapp$ <-- No CLI errors after running

приложение /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();

    }

}

приложение / Работа /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,
],

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

1 ответ

Удаление exit() решил проблему - это странно, так как в руководстве по PHP написано, что вы можете использовать exit() выйти из программы "нормально"

Это верно для обычных программ, но работа в очереди в Laravel не следует тому же жизненному циклу.

Когда система очередей обрабатывает задание, оно выполняется в существующем рабочем процессе очереди. В частности, работник очереди выбирает данные задания из серверной части и затем вызывает задание handle() метод. Когда этот метод возвращается, работник очереди запускает некоторый код для завершения задания.

Если мы выйдем с работы - позвонив exit(), die() или путем запуска фатальной ошибки - PHP также останавливает рабочий процесс, выполняющий задание, поэтому система очередей никогда не завершает жизненный цикл задания, и задание никогда не помечается как "завершенное".

Нам не нужно явно выходить с работы. Если мы хотим закончить работу раньше, мы можем просто вернуться из handle() метод:

public function handle() 
{
    // ...some code...

    if ($exitEarly) {
        return;
    }

    // ...more code...
}

Laravel также включает в себя черту, InteractsWithQueue, который предоставляет API, который позволяет работе управлять собой. В этом случае мы можем назвать delete() метод из работы, которая проявляет эту черту:

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

Но работа сообщается как проваленная. Зачем? Странно, но и в worker.log там написано: "Обработка дважды для одной работы".

Как описано выше, работа не может быть успешно завершена, потому что мы позвонили exit() Таким образом, система очередей покорно попыталась повторить задание.

Другие вопросы по тегам