2017-02-23 2 views
0

J'ai 3 processus de file d'attente beanstalkd qui s'exécutent sur la même adresse IP mais sur des ports différents. J'ai un serveur séparé exécutant le superviseur spawning php travailleurs en parallèle (20 par port beanstalkd) pour traiter la file d'attente. Mon problème est qu'il semble que deux processus peuvent réserver le même ID de travail sur le même serveur en même temps.Pheanstalk réservant le même travail beanstalkd deux fois ou plus

Voici quelques exemple de sortie de mon journal:

2017-02-23 09:59:56 --> START JOB (port: 11301 | u: 0.45138600 1487861996 | jid:1695074 | pid:30019 | j:leads_to_tags_add | tr:1) 
2017-02-23 09:59:57 --> START JOB (port: 11301 | u: 0.55024800 1487861997 | jid:1695074 | pid:30157 | j:leads_to_tags_add | tr:2) 
2017-02-23 09:59:58 --> DEL JOB (port: 11301 | u: 0.54731000 1487861998 | jid:1695074 | pid:30019 | j:leads_to_tags_add) 
2017-02-23 09:59:58 --> DEL JOB (port: 11301 | u: 0.58927900 1487861998 | jid:1695074 | pid:30157 | j:leads_to_tags_add) 

Il semble que les deux réserves se trouvent juste après l'autre, et la deuxième réserve se produit avant la première fin du processus et supprime le travail.

J'ai ajouté un compteur en redis par jobid et il est clair qu'au moment où il réserve la deuxième fois, le compteur monte une fois (tr). Le TTRR est défini sur 3600, il n'y a donc aucun moyen qu'il expire avant la fin du premier processus.

C'est ce que l'état du travail ressemble juste après le second processus réserve:

Pheanstalk\Response\ArrayResponse::__set_state(array(
    'id' => '1695074', 
    'tube' => 'action-medium', 
    'state' => 'reserved', 
    'pri' => '0', 
    'age' => '1', 
    'delay' => '0', 
    'ttr' => '3600', 
    'time-left' => '3599', 
    'file' => '385', 
    'reserves' => '2', 
    'timeouts' => '0', 
    'releases' => '0', 
    'buries' => '0', 
    'kicks' => '0', 
)) 

Ce comportement est très aléatoire, parfois un seul processus sera en mesure de réserver jusqu'à ce que les serrures d'emploi, parfois 2, parfois même 4 ou plus (rarement). Bien sûr, cela crée un nombre incohérent de tâches en double en cours d'exécution.

Version courte du code:

$this->job = $this->pheanstalk->watch($tube)->reserve($timeout); 


set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) { 
    // error was suppressed with the @-operator 
    if (0 === error_reporting()) { 
     return false; 
    } 

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline); 
}); 

$this->log_message('info', __METHOD__ . ": START JOB (" . $this->_logDetails() . " | tr:{$tries})"); 


if ($this->_process_job()) { 
    $this->log_message('info', __METHOD__ . ": FINISHED JOB (" . $this->_logDetails() . ")"); 
    $this->_delete_job(); 
} else { 
    $this->log_message('error', __METHOD__ . ": FAILED JOB (" . $this->_logDetails() . ")"); 
} 

restore_error_handler(); 

et

protected function _delete_job() 
{ 
    $this->pheanstalk->delete($this->job); 
    $this->log_message('info', __METHOD__ . ": DELETED JOB (" . $this->_logDetails() . ")"); 
} 
+0

S'il vous plaît envoyer votre code où vous «réservez» le travail, envoyez-le à travailler sur, puis «supprimer» lorsqu'il est terminé. –

+0

@AlisterBulman mis à jour avec du code – pierdevara

+0

Les problèmes se produisent-ils toujours avec un seul serveur Beanstalkd? Est-ce que tous les serveurs ont des configs différentes pour la journalisation binaire etc., et pourquoi en utiliser plus d'une de toute façon? –

Répondre

0

La question était une déconnexion TCP qui se passe dans le bit process_job de mon code. L'objet pheanstalk serait écrasé quelque part dans la chaîne d'exécution. Phoenixstalk qui vérifie le serveur beanstalkd le plus vide disponible avant d'envoyer une commande put. Il créerait alors une nouvelle instance de Pheanstalk avec les détails du meilleur serveur, l'enregistrerait comme la connexion actuelle, puis enverrait la commande.

Parfois, le travailleur peut envoyer un sous-job à la file d'attente. La bibliothèque serait initialement chargée dans le worker pour récupérer un job, et de nouveau dans process_job pour l'envoyer à la file d'attente. En raison de l'injection de dépendance dans Codeigniter, cette bibliothèque ferait référence au même objet, et à l'intérieur de process_job, elle écraserait la connexion actuelle du worker et provoquerait une déconnexion TCP.