摘要:今天跑脚本遇到一个奇怪的问题,就是请求到后期会出现程序阻塞卡死,无异常无响应,一直挂起,脚本也不会自动结束。设置允许执行的最长秒数。增加执行超时后的请求设置函数。从错误类型中,看到确实是有一些请求在秒内未能执行完毕。
今天跑脚本遇到一个奇怪的问题,就是cURL请求到后期会出现程序阻塞卡死,无异常无响应,一直挂起,脚本也不会自动结束。跟对方沟通后说,“哥们儿,是不是你们的程序有问题啊,这边研发排查了,说12点30左右没有收到你们的请求。然后我自己用网上的json工具请求了,一下就通过了”。是不是很尴尬,关键是根本不知道为什么。然后就是不停的尝试重跑脚本,偶尔有些脚本就跑过了,但好景不长,随时都可能出现无效的时候。一直看,请求一开始都是能正常完成的,越往后执行时间也变得逐渐增长,然后就可能变成死连接。就想到,肯定是cURL发送的请求有的无响应失效了,已经成僵尸连接,还一直阻塞脚本,导致资源一直存在,但是并不能继续使用。
找了各种资料,还想尝试写一个类似定时器的定西,如果脚本执行超过1分钟,则强制丢弃掉该cURL链接。不知道PHP怎么实现这样的需求,还犹豫要不要用go来实现。涉及到json,xml等,用go毕竟没有PHP方便,就去手册阅读cURL的内容,企图找到一点有用的东西。而且cURL命令行工具是有重试功能的,猜想扩展肯定也有。但是该如何配置呢?
看了PHP超时处理全面总结这篇文章中的超时,才知道因为我的代码设置cURL连接选项时只设置了连接超时时间,并没有设置执行超时时间。观察通常10秒内正常都应该返回数据,我就设置了超时和执行时间都是30秒。增加这个参数限制后,总算能捕捉到无响应的请求了,剩下的就是如何处理在规定时间内无法返回结果的资源了。
就是这几个参数没有了解过,给排查问题浪费了整整一个下午。
/** * 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秒。
Error [28]: Operation timed out after 30000 milliseconds with 0 bytes received
可以输出查看,针对这种超时,直接丢弃该次连接,重新初始化一次资源请求即可。当然这里尝试重试6次,6次都还无法正常执行完毕,就只能在想别的办法了。虽然最终并不知道为什么会有连接失效,但是这样之后,就能保证基本可以完成任务了。
我执行一个月的跑数脚本,所有超时情况就有这么多,幸运的是最终都没能等到重试6次,就请求成功了。从错误类型中,看到确实是有一些请求在30秒内未能执行完毕。
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
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/23251.html
视频地址 学徒卡夫 - 卡夫的Mac 03 - Mac下使用Docker配置PHP环境 https://www.bilibili.com/vide... 安装 Docker https://www.docker.com/docker... 下载镜像 # 安装基础镜像 - ubuntu:14.04 # 拉取镜像(拉取镜像经常会失败,尝试几次就好了) docker pull ubuntu:14.0...
视频地址 学徒卡夫 - 卡夫的Mac 03 - Mac下使用Docker配置PHP环境 https://www.bilibili.com/vide... 安装 Docker https://www.docker.com/docker... 下载镜像 # 安装基础镜像 - ubuntu:14.04 # 拉取镜像(拉取镜像经常会失败,尝试几次就好了) docker pull ubuntu:14.0...
摘要:背景说明小拽利用的写的爬虫,实验性的爬取了知乎用户的基本信息同时,针对爬取的数据,进行了简单的分析呈现。本程序抓取的是知乎对外提供用户访问的个人信息页面抓取过程需要携带用户才能获取页面。 背景说明:小拽利用php的curl写的爬虫,实验性的爬取了知乎5w用户的基本信息;同时,针对爬取的数据,进行了简单的分析呈现。demo 地址 php的spider代码和用户dashboard的展现代码...
摘要:背景说明小拽利用的写的爬虫,实验性的爬取了知乎用户的基本信息同时,针对爬取的数据,进行了简单的分析呈现。本程序抓取的是知乎对外提供用户访问的个人信息页面抓取过程需要携带用户才能获取页面。 背景说明:小拽利用php的curl写的爬虫,实验性的爬取了知乎5w用户的基本信息;同时,针对爬取的数据,进行了简单的分析呈现。demo 地址 php的spider代码和用户dashboard的展现代码...
摘要:背景说明小拽利用的写的爬虫,实验性的爬取了知乎用户的基本信息同时,针对爬取的数据,进行了简单的分析呈现。本程序抓取的是知乎对外提供用户访问的个人信息页面抓取过程需要携带用户才能获取页面。 背景说明:小拽利用php的curl写的爬虫,实验性的爬取了知乎5w用户的基本信息;同时,针对爬取的数据,进行了简单的分析呈现。demo 地址 php的spider代码和用户dashboard的展现代码...
阅读 2042·2021-10-08 10:21
阅读 2416·2021-09-29 09:34
阅读 3452·2021-09-22 15:51
阅读 4806·2021-09-22 15:46
阅读 2279·2021-08-09 13:42
阅读 3344·2019-08-30 15:52
阅读 2692·2019-08-29 17:13
阅读 1504·2019-08-29 11:30