2015-04-24 1 views
8

Я создаю сайт с использованием Laravel 5. Я использую очереди с beanstalkd с двумя пробирками. У меня 10 работников, которых контролирует daemontools. 5 рабочих трубок A и B. Другие 5 рабочих только обрабатывают трубу B.Laravel 5: Несколько рабочих - Не удается удалить задание XXXXXX: NOT_FOUND

Вещи работают отлично в течение большей части времени, но иногда трубка B кажется запертой. Журналы показывают, что рабочие бросают исключение.

[2015-04-24 07:09:36] local.ERROR: exception 'Pheanstalk\Exception\ServerException' with message 'Cannot delete job 273812: NOT_FOUND' in /x/website/vendor/pda/pheanstalk/src/Command/DeleteCommand.php:44 
Stack trace: 
#0 /x/website/vendor/pda/pheanstalk/src/Connection.php(121): Pheanstalk\Command\DeleteCommand->parseResponse('NOT_FOUND', NULL) 
#1 /x/website/vendor/pda/pheanstalk/src/Pheanstalk.php(384): Pheanstalk\Connection->dispatchCommand(Object(Pheanstalk\Command\DeleteCommand)) 
#2 /x/website/vendor/pda/pheanstalk/src/Pheanstalk.php(67): Pheanstalk\Pheanstalk->_dispatch(Object(Pheanstalk\Command\DeleteCommand)) 
#3 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Jobs/BeanstalkdJob.php(73): Pheanstalk\Pheanstalk->delete(Object(Pheanstalk\Job)) 
#4 /x/website/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(46): Illuminate\Queue\Jobs\BeanstalkdJob->delete() 
#5 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php(126): Illuminate\Queue\CallQueuedHandler->call(Object(Illuminate\Queue\Jobs\BeanstalkdJob), Array) 
#6 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Jobs/BeanstalkdJob.php(51): Illuminate\Queue\Jobs\Job->resolveAndFire(Array) 
#7 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(207): Illuminate\Queue\Jobs\BeanstalkdJob->fire() 
#8 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(159): Illuminate\Queue\Worker->process('beanstalkd', Object(Illuminate\Queue\Jobs\BeanstalkdJob), '20', '120') 
#9 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(113): Illuminate\Queue\Worker->pop(NULL, NULL, '120', 3, '20') 
#10 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(85): Illuminate\Queue\Worker->runNextJobForDaemon(NULL, NULL, '120', 3, '20') 
#11 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(101): Illuminate\Queue\Worker->daemon(NULL, NULL, '120', 128, 3, '20') 
#12 /x/website/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(67): Illuminate\Queue\Console\WorkCommand->runWorker(NULL, NULL, '120', 128, true) 
#13 [internal function]: Illuminate\Queue\Console\WorkCommand->fire() 
#14 /x/website/vendor/laravel/framework/src/Illuminate/Container/Container.php(523): call_user_func_array(Array, Array) 
#15 /x/website/vendor/laravel/framework/src/Illuminate/Console/Command.php(115): Illuminate\Container\Container->call(Array) 
#16 /x/website/vendor/symfony/console/Symfony/Component/Console/Command/Command.php(257): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#17 /x/website/vendor/laravel/framework/src/Illuminate/Console/Command.php(101): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#18 /x/website/vendor/symfony/console/Symfony/Component/Console/Application.php(874): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#19 /x/website/vendor/symfony/console/Symfony/Component/Console/Application.php(195): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Queue\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#20 /x/website/vendor/symfony/console/Symfony/Component/Console/Application.php(126): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#21 /x/website/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(94): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#22 /x/website/artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 
#23 {main} 

Мне интересно, может ли эта проблема возникнуть из-за того, что несколько работников отправились на ту же работу. Это возможно или есть какой-то мьютекс, чтобы контролировать это?

Что еще может вызвать это?

ответ

13

Команда queued занимает слишком много времени, и проблема была вызвана значением TTR на трубке в beanstalkd, но нет необходимости изменять это значение.

В двух словах beanstalkd будет сохранять задание только на максимальный период времени (вплоть до TTR), а затем он предположит, что что-то пошло не так и возвращает задание обратно в состояние готовности.

Вместо этого можно периодически прикоснуться к заданию по сбросу таймера резервирования.

В Laravel я добавил это в свой класс приложений \ Commands \ Command, и я периодически вызываю его внутри циклов на длинных рабочих заданиях.

public function touch() 
{ 
    if (method_exists($this->job, 'getPheanstalk')) { 
     $this->job->getPheanstalk()->touch($this->job->getPheanstalkJob()); 
    } 
} 
+0

Могу ли я получить разъяснения относительно того, как именно я это реализую? Если вы сказали, что нужно добавить его в App \ Command, вы говорите, что я делаю новую команду под названием TouchCommand.php, например, потому что в командах, которые я обычно вижу, это конструктор и дескриптор, поэтому не уверен, где это происходит. Тогда в моей реальной работе, как мне это назвать? – dmotors

+0

Вы можете просто поместить эту функцию прямо в класс Command. Ваши другие классы команд будут расширяться от него и наследовать эту функцию. Затем в методе handle() вы можете периодически называть $ this-> touch() для сброса таймера. – Kebian

+3

Для справки Я использовал этот код в своем абстрактном классе Job, а затем вызвал метод с помощью моих длительных рабочих заданий. – george

1

Была такая же проблема. Мои задания заняли более 60 секунд. Увеличение значения ttr в очереди конфигурации на стандартной трубке сделало трюк. Надеюсь, что помогает.

+0

Спасибо. Мне также удалось выделить его на работу, которая слишком долго заканчивается. Комбинация оптимизации моего кода и изменения ttr, как вы предлагаете, может решить проблему. Я расскажу об этом с моими выводами. – Kebian

+1

Если ваши задачи идемпотентны, тогда это будет ОК, иначе просто подумайте, что может случиться, если задача внезапно займёт намного больше времени? Подход к тому, чтобы прикоснуться к заданию, намного безопаснее. Это также позволяет применять его только к заданию, а не ко всей очереди. Некоторым элементам, возможно, никогда не понадобится очень долгое время, и на самом деле они могут быть быстро пойманы. –

0

Чтобы быть более точным с касанием, вы можете использовать рабочую функцию, представленную выше, и выполните следующие действия в работе:

1) Объявите свойство и установить его значение в конструкторе:

Protected $ttr; 

public function __construct() { 
    $this->ttr = time(); 
} 

2) Затем измерьте разницу во времени внутри вашей петли. В моем случае я загружал и обрезал тысячи изображений, поэтому в этом цикле я вставил следующее:

//With a ttr of 60. 
if((time() - 50) >= $this->ttr) { //If over 50 seconds since ttr start, 
    $this->touch(); //reset ttr, 
    $this->ttr = time(); //and set new time. 
} 
Смежные вопросы