2015-04-24 12 views
8

Sto creando un sito Web utilizzando Laravel 5. Sto utilizzando le code con beanstalkd con 2 tubi. Ho 10 lavoratori monitorati da daemontools. 5 lavoratori lavorano i tubi A e B. Gli altri 5 lavoratori lavorano solo la provetta B.Laravel 5: Multiple worker - Impossibile eliminare job XXXXXX: NOT_FOUND

Le cose funzionano molto la maggior parte del tempo, ma a volte il tubo B sembra bloccarsi. I registri mostrano che i lavoratori lanciano un'eccezione.

[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} 

Mi chiedo se il problema potrebbe essere causato da diversi lavoratori in corso per lo stesso lavoro. È possibile o esiste una specie di mutex per controllarlo?

Cos'altro potrebbe causare questo?

risposta

13

Il comando in coda richiedeva troppo tempo e il problema era causato dal valore TTR sul tubo in beanstalkd, ma non è necessario modificare tale valore.

In breve, beanstalkd manterrà il lavoro riservato solo per un periodo di tempo massimo (fino al TTR) e quindi supporrà che qualcosa sia andato storto e restituisca il lavoro allo stato pronto.

Invece, è possibile periodicamente toccare il processo per reimpostare il timer di prenotazione.

In Laravel, l'ho aggiunto alla mia classe App \ Commands \ Command e periodicamente lo chiamo all'interno di cicli su lavori di lunga durata.

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

Posso ottenere qualche chiarimento su come esattamente lo implemento? Se hai detto di aver bisogno di aggiungerlo all'App \ Command, stai dicendo che faccio un nuovo comando chiamato TouchCommand.php ad esempio con quello perché nei comandi tutto quello che vedo solitamente è costruttore e gestisco quindi non sono sicuro di dove andare. Quindi nel mio vero lavoro come lo chiamo? – dmotors

+0

Puoi semplicemente inserire la funzione direttamente nella classe Command. Le altre classi di comando si estenderanno da essa e erediteranno tale funzione. Quindi nel loro metodo handle() è possibile chiamare periodicamente $ this-> touch() per reimpostare il timer. – Kebian

+3

Per riferimento ho usato questo codice sulla mia classe Job astratta e poi ho chiamato il metodo con i miei lavori lunghi in esecuzione. – george

1

Aveva lo stesso problema. I miei lavori sono durati più di 60 secondi. Aumentare il valore ttr nella coda di configurazione sul tubo predefinito ha fatto il trucco. Spero che questo aiuti.

+0

Grazie. Sono anche riuscito a isolarlo in lavori che impiegano troppo tempo per essere completati. Una combinazione di ottimizzazione del mio codice e modifica del TTR come suggerito potrebbe risolverlo. Aggiornerò qui con i miei risultati. – Kebian

+1

Se i tuoi compiti sono idempotenti, questo sarà OK altrimenti pensa solo cosa potrebbe accadere se un compito richiede molto più tempo? L'approccio per continuare a toccare il lavoro è molto più sicuro. Ciò consente anche di applicarlo solo al lavoro che si desidera e non all'intera coda. Alcuni articoli potrebbero non richiedere mai molto tempo e in effetti potrebbero voler essere catturati rapidamente. –

0

Per essere più precisi con la vostra toccante, è possibile utilizzare la funzione di lavoro previsto sopra e fare quanto segue nel tuo lavoro:

1) dichiarare una proprietà e impostare il suo valore nel costruttore:

Protected $ttr; 

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

2) Quindi misurare la differenza di tempo all'interno del ciclo. Nel mio caso, stavo scaricando e ritagliando migliaia di immagini, quindi in quel ciclo ho inserito quanto segue:

//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. 
}