Я использую последнюю версию Homestead.
У меня также есть Laravel Horizon.
Я использую Redis в качестве драйвера очереди.
Laravel является версией 5.6 и является новой установкой.
То, что происходит, — мои рабочие места терпят неудачу (даже если работа завершается правильно).
Я запускаю работу через командную строку с помощью пользовательской команды:
vagrant@homestead:~/myapp$ artisan crawl:start
vagrant@homestead:~/myapp$ <-- No CLI errors after running
<?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();
}
}
<?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();
}
}
<?php
namespace MyApp;
class Crawl
{
public function start()
{
ini_set('memory_limit','256M');
set_time_limit(3600);
echo "Started.";
sleep(30);
echo "Exited.";
exit();
}
}
[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
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
[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
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'retry_after' => 90,
'block_for' => null,
],
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);
Удаление
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()
Таким образом, система очередей покорно попыталась повторить задание.
Других решений пока нет …