我有3个beanstalkd队列进程在相同的ip但不同的端口上运行。我有一个单独的服务器运行主管并行生成php worker(每个beanstalkd端口20个)来处理队列。我的问题是,似乎两个进程可以在同一时间在同一台服务器上保留相同的作业ID。
以下是我日志中的一些示例输出:
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)
似乎两个储备相继发生,第二个储备发生在第一个流程结束并删除工作之前。
我在每个jobid的redis中添加了一个计数器,很清楚,当它第二次保留时,计数器上升了一次(tr)。 TTRR设置为3600,因此在第一个过程完成之前无法过期。
这是第二个流程保留之后的工作状态:
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',
))
此行为非常随机,有时只有一个进程能够保留,直到作业锁定,有时2个,有时甚至4个或更多(很少)。当然,这会导致执行的重复作业数量不一致。
代码的简短版本:
$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();
和
protected function _delete_job()
{
$this->pheanstalk->delete($this->job);
$this->log_message('info', __METHOD__ . ": DELETED JOB (" . $this->_logDetails() . ")");
}
答案 0 :(得分:0)
问题是我的代码的process_job位中发生了TCP断开连接。 pheanstalk对象将在执行链的某处被覆盖。
我有一个包装pheanstalk的库,它在发送put命令之前检查可用的最空的beanstalkd服务器。然后,它将创建一个具有最佳服务器详细信息的新Pheanstalk实例,将其另存为当前连接,然后调度该命令。
有时工作人员可以将子工作发送到队列。最初将库加载到工作程序中以获取作业,并再次在process_job中将其发送到队列。由于Codeigniter中的依赖注入,该库将引用相同的对象,并且在process_job内部它将覆盖工作者的当前连接并导致TCP断开。