Search code examples
phplaravelsoapsoap-clientlaravel-queue

SoapClient in a Laravel Job "cannot connect to host" after a while when using queue:work


I am using a Laravel Job to schedule a Web Service call, and a single request just works fine, meaning there is no problem in connection to the host, nor any other, the web service communication is OK.

I use WSDL SoapClient initialization, so something like

$soapClient = new \SoapClient($wsdl,[
        'trace' => 1,
        'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
        'keep_alive' => true,
        'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
        'cache_wsdl' => WSDL_CACHE_MEMORY
]);

Once the queue started to get serious traffic, I enabled the queue spooling with

php artisan queue:work --queue=soapQueue

As expected, requests are spooled and processed, with a pretty decent speed, more or less 6 requests per second, not bad if you consider that each SOAP call takes more or less 150ms, so 900ms for Web Service and only 100ms for processing the queue. For each request we have an average of 16ms for queue processing.

After a while (less than a minute) something changes: each and every web service call fails with the exception

[2019-03-29 09:50:29] local.ERROR: Could not connect to host  
[2019-03-29 09:50:29] local.ERROR: #0 [internal function]: SoapClient->__doRequest('<?xml version="...', 'https://ws.host...', 'PAR_ServiceCall...', 1, 0)

At first I was suspecting to be hitting too hard the host, so that I was temporarily banned, but this wasn't the case: if I quit the process and restart it, it immediately starts to process messages.

Moreover, if I use queue:listen instead of queue:work (meaning that you reload the Laravel environment with each job, as explained in What is the difference queue:work and queue:listen, this does not happen, evidently caused by the reload of the environment.

Using queue:listen the performance degrades quite significantly, passing from 6 messages per second to 3, meaning that with the same average of 150ms needed for each call, summing up to 450ms, the queuing process takes the remaining 550ms, that is more or less 180ms for each call, 11 times more than before.

It perfectly makes sense, but I was wondering if there is a way to prevent this error with SoapClient.


Solution

  • After A LOT of attempts, I stumbled upon a solution that prevented this behavior to happen.

    The problem was all about SoapClient keep_alive indicator.

    Creating the SoapClient with a false keep_alive flag

    $soapClient = new \SoapClient($wsdl,[
        'trace' => 1,
        'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
        'keep_alive' => false,
        'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
        'cache_wsdl' => WSDL_CACHE_MEMORY
    ]);
    

    you prevent it to establish a keep-alive connection, so each call will create a brand new connection to the web service.

    This may not be super optimized, but in my long-running script context prevents the weird error that I had, and testing this for a long time (hours) the error never came back