解决SOAP客户端在请求https时设置超时时间无效导致进程卡死问题
目前有一个进程服务脚本是不断查询渠道的接口,但是历史问题是有时订单量大的时候进程会卡死,这次遇到了进行排查一下:
首先获取该进程ID
ps -aux | grep QueryABC.php sync360 11115 0.0 0.0 6564 864 ? Ss 14:00 0:00 /bin/sh -c /usr/local/bin/php /xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/QueryABC.php BILL99DF 10-8>> /home sync360 11124 0.0 0.4 361628 17296 ? S 14:00 0:04 /usr/local/bin/php /xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/QueryABC.php BILL99DF 10-8 sync360 25230 0.0 0.0 63384 872 pts/0 S+ 15:28 0:00 grep QueryABC.php
strace查看该进程正在持续的状态
sudo strace -T -tt -e trace=all -p 11124 [sudo] password for ancongcong: Process 11124 attached - interrupt to quit 15:33:07.259044 read(9,
lsof查看进程的所使用的文件
lsof -p 11124 .... php 11124 sync360 mem REG 8,1 23736 3211320 /lib64/libnss_dns-2.5.so php 11124 sync360 0r FIFO 0,6 1522728709 pipe php 11124 sync360 1w REG 8,1 4088819 1869737 /xxxx/xxxx/xxxx/xxxx/logs/QueryABC.log php 11124 sync360 2w FIFO 0,6 1522728710 pipe php 11124 sync360 3w CHR 1,3 982 /dev/null php 11124 sync360 4u IPv4 1522728838 TCP 211.151.122.234:46004->10.117.128.47:rtmp-port (CLOSE_WAIT) php 11124 sync360 5wW REG 8,1 0 2704363 /xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/xxxx/lockfile/QueryABC.php.BILL99DF.10-8 php 11124 sync360 6u IPv4 1522728841 TCP 211.151.122.234:51019->10.117.128.46:rtmp-port (CLOSE_WAIT) php 11124 sync360 7w REG 8,1 31960384 1869789 /xxxx/xxxx/xxxx/xxxx/logs/XXXX_info.log.20180118 php 11124 sync360 8w REG 8,1 18151722 1869806 /xxxx/xxxx/xxxx/xxxx/logs/XXXX_QRY_info.log.20180118 php 11124 sync360 9u IPv4 1522729884 TCP 211.151.122.234:54976->61.152.114.130:https (ESTABLISHED)
sudo netstat -tunpa | grep 11124 tcp 0 0 211.151.122.234:54976 61.152.114.130:443 ESTABLISHED 11124/php tcp 1 0 211.151.122.234:51019 10.117.128.46:3500 CLOSE_WAIT 11124/php tcp 1 0 211.151.122.234:46004 10.117.128.47:3500 CLOSE_WAIT 11124/php
可以发现最终是停留在https的链接建立,等待获取数据,查看此处代码
ini_set('default_socket_timeout',30); $scOptions = array('connection_timeout' => 30); $clientObj = new SoapClient( $wsdl , $scOptions);
当前版本php较老,这里是有个bug的在https链接请求时SOAPClient的超时时间是不生效,最终采取如下方案解决此问题:
复写SOAPClient,在https时候使用curl来完成请求解决问题
<?php class SoapClientTimeout extends SoapClient { private $timeout; public function __setTimeout($timeout) { if (!is_int($timeout) && !is_null($timeout)) { throw new Exception("Invalid timeout value"); } $this->timeout = $timeout; } public function __doRequest($request, $location, $action, $version, $one_way = FALSE) { if (!$this->timeout) { // Call via parent because we require no timeout $response = parent::__doRequest($request, $location, $action, $version, $one_way); } else { // Call via Curl and use the timeout $curl = curl_init($location); curl_setopt($curl, CURLOPT_VERBOSE, FALSE); curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($curl, CURLOPT_POST, TRUE); curl_setopt($curl, CURLOPT_POSTFIELDS, $request); curl_setopt($curl, CURLOPT_HEADER, FALSE); curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: text/xml")); curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeout); $response = curl_exec($curl); if (curl_errno($curl)) { throw new Exception(curl_error($curl)); } curl_close($curl); } // Return? if (!$one_way) { return ($response); } } }
文章来源:
Author:司马他
link:https://www.congcong.us/post/soap_https_timeout_not_useful_problem.html