php实现curl重试机制

时间:2022-12-29 20:08:14

前言,最近接手的项目中需要跨网络调用其他项目服务的API。由于网络中存在各种复杂的因素,导致curl请求偶尔出现下面错误。

Failed connect to www.xxx.com:80; Connection timed out

做了一下几点尝试:

  1. 抓包分析,也没有分析出个所以然。

  2. 以为是尝试连接的等待时间太小了,于是通过调整增大CURLOPT_CONNECTTIMEOUT参数,发现也无济于事。

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); //在尝试连接时等待的秒数

重试机制 由于之前的工作经历中,经常遇到各种偶发无法连接服务的情况如mysql等等,都是通过增加重试连接的方式解决的。

于是根据过往经验,干脆写了个curl请求重试机制,轻松解决了问题。特此分享一下:

    $ch = curl_init($url);
    //curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
    //curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-type:application/json;charset=utf-8"));
    curl_setopt($ch, CURLOPT_TIMEOUT, 1800);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); //在尝试连接时等待的秒数

    if (!empty($options)) {
        curl_setopt_array($ch, $options);
    }

    $data = curl_exec($ch);
    $curlErrno = curl_errno($ch);


    //curl增加重试机制
    $retryTimes=0;
    $maxRetryTimes=10;
    if($curlErrno)
    {
        for($retryTimes=0;$retryTimes<$maxRetryTimes;$retryTimes++)
        {
            $retryTimes++;

            $data = curl_exec($ch);
            $curlErrno = curl_errno($ch);
            if(!$curlErrno)
            {
                error_log("CURL重试{$retryTimes}次后成功".addslashes(json_encode(curl_getinfo($ch), JSON_UNESCAPED_UNICODE)));
                break;
            }
            sleep(1);
        }
    }

	//错误监控告警
    if ($curlErrno) {
        //curl请求异常,往上层抛出异常信息
        $errorMessage = 'CURL请求出错了!';
        $errorMessage .= '【地址】:' . $url . '。';
        $errorMessage .= '【方法】: GET。';
        $errorMessage .= '【参数】:' . addslashes(json_encode($postdata, JSON_UNESCAPED_UNICODE)) . '。';
        $errorMessage .= '【错误信息】:' . curl_error($ch) . "({$curlErrno}).";
        $errorMessage .= '【CURL_INFO】:' . addslashes(json_encode(curl_getinfo($ch), JSON_UNESCAPED_UNICODE)) . '。';

        #增加调用信息
        $backtrace = "";
        $backtraceList = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        foreach ($backtraceList as $v) {
            $fileName = $v['file'] ?? '';
            $lineNo = $v['line'] ?? 0;
            $className = $v['class'] ?? '';
            $functionName = $v['function'] ?? '';
            $backtrace .= "{$fileName} - {$lineNo} - {$className}::{$functionName}()" . '。';
        }
        $errorMessage .= '【调用】:' . $backtrace;
        $errorMessage .= '【重试次数】:' . $retryTimes;
        $errorMessage .= '【处理服务器】:' . gethostname();


        $errorMessage = str_replace(array("\r\n", "\r", "\n", "   "), '', $errorMessage);
	
	  //告警通知
        qywx_robot_error_notice($errorMessage);
        unset($errorMessage, $backtrace, $backtraceList);

        //throw new \Exception(curl_error($ch),$errorNo);
        //return false;
    }

    curl_close($ch);

    return $data;