PHP多进程中变量初始化引发的血案

        “建哥,建哥,有空没,帮我看个诡异的问题。大部分数据是正常更新的,个别数据没有更新到,找半天了不知道什么原因。”

        前不久小伙伴在排查一个库存自动更新的问题的,时候找我看了一个问题。

        需求流程如下:

PHP多进程中变量初始化引发的血案

由于数据量变更非常频繁,小伙伴这里采用了多进程处理(Swoole的Server和Client模式):

PHP多进程中变量初始化引发的血案

下面我们来看看具体的代码:

//创建Server对象,监听 127.0.0.1:9998 端口$obj = new Daemon_Update_Stock_Ebay_Server();$conf = $obj->get_config('swoole.ini', 'ebay');$serv = new swoole_server($conf->autoUpdateStock->host, $conf->autoUpdateStock->port);
$serv->set([    'open_length_check' => true,    'package_length_type' => "N", // 4个字节    'package_length_offset' => 0,    'package_body_start' => 4, // 表示只计算包体的长度,不包含长头的长度    'package_max_length' => 80000, // 最大包长    'worker_num' => 1,    'max_request' => 5000,    'task_worker_num' => 32,    'task_max_request' => 5000,]);
$serv->on('Task', function ($serv, $taskId, $fromId, $data) use ($obj) {    $obj->start($data);});
class Daemon_Update_Stock_Ebay_Server extends Ebay_Base{    public $ebayUpdateStockObj;
    public function __construct()    {        parent::__construct();        $this->ebayUpdateStockObj = new Daemon_Update_Stock_Ebay();    }
    /**     * 开始执行     * @param $queueId     */    public function start($queueId)    {        try{            $this->ebayUpdateStockObj->setQueueId($queueId);            $updateStockObj = new Daemon_Update_Stock($this->ebayUpdateStockObj);            $updateStockObj->runNew();        }catch(Exception $e){            $msg = $e->getMessage();            $this->log->write_custom("#ERROR-队列ID({$queueId})-{$msg}",__FILE__, __LINE__, $this->log_suffix, $this->log->ERR);        }    }}
class Daemon_Update_Stock {  private $obj;  private $queueData = null;  private $ruleList = null;    public function __construct(Daemon_Update_Stock_Interface $obj)  {      $this->obj = $obj;      $this->init();  }    public function runNew()  {      //队列数据JSON化(日志记录需要)      $queueDataJson = @json_encode($this->queueData);        //获取使用该SKU的所有Listing      $allList = $this->obj->getAllList($this->queueData['goods_sn']);        foreach ( $this->ruleList as $ruleDetail ){          //判断SKU是否满足规则条件      }        //更新OMS变更库存队列的状态为已执行      $this->obj->updateOmsQueueStatusToSuccess();  }}
abstract class Daemon_Update_Stock_Abstract implements Daemon_Update_Stock_Interface{    protected $platformNo = null;    protected $platformTable = null;    protected $baseObj = null;    protected $queueId = null;    protected $systemLogConfig = null;    /**     * 优先级高的规则已经更新过该条sku商品,那么后边的规则将忽略该条sku商品     * @var array     */    protected $haveRunRuleGoodsId = [];}
foreach($val->_source->goodsList as $goodsList) {    //排除掉已经跑过的库存规则(针对于库存规则优先级排序)    if(in_array($goodsList->id,$this->haveRunRuleGoodsId)){        continue;    }
    //处理业务逻辑
    //已经跑过规则的sku商品记录到全局变量中,其它规则跑到就直接跳过    $this->haveRunRuleGoodsId[] = $goodsList->id;}

从代码中我们可以看出,数据haveRunRuleGoodsId在定义的时候有初始化,简单看代码,好像确实没有问题,有初始化啊。

下面我来告诉大家到底哪出了问题了:

1、我们先看看,我们变量初始化是在什么时候做  的:Daemon_Update_Stock_Ebay_Server 的构造函数中

2、再来看看我们的Swoole设置:‘task_max_request’ => 5000, 也就是说我们执行5000次的task任务后才会重启Service端

3、我们再来看看下面的处理流程

PHP多进程中变量初始化引发的血案

看到这里是不是很清楚了呢:我们在接收到数据的时候,没有对haveRunRuleGoodsId 进行初始化,所有当同一个SKU投递到同一个子进程的时候,因为 haveRunRuleGoodsId 里面已经存在了,所以不会更新。

我们需要做的就是,在每次执行前清空掉:

/** * 库存自动更新入口 * @return array */public function runNew(){    //队列数据JSON化(日志记录需要)    $queueDataJson = @json_encode($this->queueData);
    //获取sku商品的货源状态    $sourceStatus = $this->obj->getSkuSourceStatus($this->queueData['goods_sn']);    //获取使用该SKU的所有Listing    $allList = $this->obj->getAllList($this->queueData['goods_sn']);
    //每投递一次初始化已跑数据,防止同一sku投递到同一个task,这种情况后面就不会更新(注)    $this->obj->resetHaveRunRuleGoodsId();        //处理业务。。。。}
public function resetHaveRunRuleGoodsId(){  $this->haveRunRuleGoodsId = [];}

到此问题解决:我们在初始化变量的时候不是在构造函数里面初始化就万事大吉了,还得考虑这个变量的生命周期是怎么样的。

未经允许不得转载:PHP100中文网 - 中国第一档PHP资源分享门户 » PHP多进程中变量初始化引发的血案

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏