模拟延时队列http请求重发机制

背景描述:近期开发中遇到请求第三方接口有可能遇到超时等情况导致用户支付完成之后未通知到第三方,与第三方沟通协商之后可以做一个重发机制来处理该问题(真正的网络错误该方法无法处理)。订单也要同时更新为最终请求通知第三方状态成功状态。

话不多说直接上码

private $retryNum = 3;   重试次数
/**
     * 加入重试队列
     * @param $result  curl请求结果
     * @param $url    url
     * @param $header   header头
     * @param $method   请求方式
     * @param $apiData    请求参数
     * @param $adminInfo   其他参数
     * @param $orderNo   订单号
     * @return string
     */
    public function addRetryQueue($result, $url, $header, $method, $apiData, $adminInfo, $orderNo)
    {
        if (isset($result['resCode']) && $result['resCode'] !== 0) {
            $apiData['retry_num'] = isset($apiData['retry_num']) ? $apiData['retry_num'] + 1 : 1;
            $info['ukey'] = $adminInfo['ukey'];
            $info['pre_table'] = $adminInfo['pre_table'];
            $info['orderno'] = $orderNo;
            //判断请求次数
//            if ($apiData['retry_num'] <= $this->retryNum) {
            list($usec, $sec) = explode(" ", microtime());
            $microtime = (int)(((float)$usec + (float)$sec) * 1000);   //使用毫秒级防止并发
            RedisInstance::getInstance()->zAdd('Queue', $microtime + 6000, json_encode([$url, $method, $apiData, $header, $info]));
//            }
        }
        return '';
    }


使用swoft框架实时监听队列情况

zRange('yQueue', 0, 0, true);
            //current()  数组中的当前元素的值   key()返回数组内部指针当前指向元素的键名
            if ($item && current($item) <= $microtime) {
                $queueData = json_decode(key($item), true);
                if ($queueData) {
                    list($url, $method, $queryData, $header, $adminInfo) = $queueData;
                    $retry_num = $queryData['retry_num'];
                    unset($queryData['retry_num']);
                    $redis->zRem('Queue', key($item));
                    //curl请求重试  此处自行写入curl模拟请求,可记录日志之类的
                    $responseData //请求结果
                    $queryData['retry_num'] = $retry_num;
                    $this->addRetryQueue($responseData, $url, 'POST', $queryData, $adminInfo, $adminInfo['orderno']);
                  
                }
            }
        }

    }

    public function check(): bool
    {
        return true;
    }

    /**
     * 失败数据添加到延时重试队列
     * @param $result
     * @param $url
     * @param $header
     * @param $method
     * @param $apiData
     * @param $adminInfo
     * @param $orderNo
     * @throws \Swoft\Db\Exception\MysqlException
     */
    private function addRetryQueue($result, $url, $header, $method, $apiData, $adminInfo, $orderNo)
    {
        $redis = App::getBean(Redis::class);
        if (isset($result['resCode']) && $result['resCode'] !== 0) {
            $apiData['retry_num'] = isset($apiData['retry_num']) ? $apiData['retry_num'] + 1 : 1;
            $info['ukey'] = $adminInfo['ukey'];
            $info['pre_table'] = $adminInfo['pre_table'];
            $info['orderno'] = $orderNo;
            //判断请求次数
            if ($apiData['retry_num'] <= 3) {
                list($usec, $sec) = explode(" ", microtime());
                $microtime = (int)(((float)$usec + (float)$sec) * 1000);
                $redis->zAdd('Queue', $microtime + 6000, json_encode([$url, $method, $apiData, $header, $info]));
            } else {
                //重试3次失败后记录入库
                $apiData['header'] = $header;
                $apiData['method'] = $method;
                $insertData['url'] = $url;
                $insertData['request_params'] = json_encode($apiData, JSON_UNESCAPED_UNICODE);
                $insertData['result_data'] = json_encode($result, JSON_UNESCAPED_UNICODE);
                $insertData['created_at'] = date('Y-m-d H:i:s');
                Query::table($adminInfo['pre_table'] . 'api_retry_log')->insert($insertData)->getResult();
            }
        } else {
            //如果重试成功修改订单状态
            Query::table($adminInfo['pre_table'] . 'carpay_order')->where('orderno', $orderNo)->update(['status' => 2, 'pay_time'=> time()])->getResult();
        }
    }
}

 

你可能感兴趣的:(curl)