php扩展cURL执行中途无响应

今天跑脚本遇到一个奇怪的问题,就是cURL请求到后期会出现程序阻塞卡死,无异常无响应,一直挂起,脚本也不会自动结束。跟对方沟通后说,“哥们儿,是否是大家的程序有问题啊,这边研发排查了,说12点30左右没有收到大家的请求。而后我本身用网上的json工具请求了,一下就经过了”。是否是很尴尬,关键是根本不知道为何。而后就是不停的尝试重跑脚本,偶尔有些脚本就跑过了,但好景不长,随时均可能出现无效的时候。一直看,请求一开始都是能正常完成的,越日后执行时间也变得逐渐增加,而后就可能变成死链接。就想到,确定是cURL发送的请求有的无响应失效了,已经成僵尸链接,还一直阻塞脚本,致使资源一直存在,可是并不能继续使用。php

找了各类资料,还想尝试写一个相似定时器的定西,若是脚本执行超过1分钟,则强制丢弃掉该cURL连接。不知道PHP怎么实现这样的需求,还犹豫要不要用go来实现。涉及到json,xml等,用go毕竟没有PHP方便,就去手册阅读cURL的内容,企图找到一点有用的东西。并且cURL命令行工具是有重试功能的,猜测扩展确定也有。可是该如何配置呢?json

看了PHP超时处理全面总结这篇文章中的超时,才知道由于个人代码设置cURL链接选项时只设置了链接超时时间,并无设置执行超时时间。观察一般10秒内正常都应该返回数据,我就设置了超时和执行时间都是30秒。增长这个参数限制后,总算能捕捉到无响应的请求了,剩下的就是如何处理在规定时间内没法返回结果的资源了。segmentfault

就是这几个参数没有了解过,给排查问题浪费了整整一个下午。curl

/**
 * CURLOPT_TIMEOUT设置cURL容许执行的最长秒数。
 * CURLOPT_TIMEOUT_MS设置cURL容许执行的最长毫秒数。(在cURL7.16.2中被加入。从PHP5.2.3起可以使用。)
 * CURLOPT_CONNECTTIMEOUT在发起链接前等待的时间,若是设置为0,则无限等待。
 * CURLOPT_CONNECTTIMEOUT_MS尝试链接等待的时间,以毫秒为单位。若是设置为0,则无限等待。在cURL7.16.2中被加入。从PHP5.2.3开始可用。
 * CURLOPT_DNS_CACHE_TIMEOUT设置在内存中保存DNS信息的时间,默认为120秒。
 */

增长执行超时后的请求设置函数。函数

/**
 * curl请求
 *
 * @param $url
 * @param string $postData
 * @param int $timeout
 * @return array|mixed
 * @throws Exception
 */
protected static function post($url, $postData = '', $timeout = 5)
{
    $ret = array();
    $times = 5;
    do {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        if ($postData != '') {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        // 重要, 该处不能丢 curl 执行最大秒数
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        $output = curl_exec($ch);
        if ($errNo = curl_errno($ch)) {
            error_log("Error [$errNo]: " . curl_error($ch));
        } else {
            $ret = json_decode($output, true);
            // 解析的结果集为空时中止查询
            if (!is_array($ret) && !trim($ret)) {
                throw new Exception(__METHOD__ . ": cURL调用失败, 信息为: " . $output);
            }
            unset($output);
        }
        curl_close($ch);
        if (isset($ret[0]) && $ret[0]) {
            return $ret;
        }
    } while ($times--);
    exit(__METHOD__ . ": cURL请求重试至 {$times} 次后仍无响应, 执行退出");
}

超时时的提示信息设置如:工具

error_log("Error [$errNo]: " . curl_error($ch));

我设置的链接时间和执行时间限制都是30秒。post

Error [28]: Operation timed out after 30000 milliseconds with 0 bytes received

能够输出查看,针对这种超时,直接丢弃该次链接,从新初始化一次资源请求便可。固然这里尝试重试6次,6次都还没法正常执行完毕,就只能在想别的办法了。虽然最终并不知道为何会有链接失效,可是这样以后,就能保证基本能够完成任务了。url

超时

我执行一个月的跑数脚本,全部超时状况就有这么多,幸运的是最终都没能等到重试6次,就请求成功了。从错误类型中,看到确实是有一些请求在30秒内未能执行完毕。spa

Error [28]: Operation timed out after 30000 milliseconds with 0 bytes received
Error [28]: Operation timed out after 30000 milliseconds with 0 bytes received
Error [28]: Operation timed out after 30000 milliseconds with 62399 out of 323196 bytes received
相关文章
相关标签/搜索