解决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);
        }
    }
}
0条留言