From 2114cd75206cdb2851b731c1147afd6d94630ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Wed, 31 Oct 2018 10:27:25 +0100 Subject: [PATCH] Support timeouts for SOAP requests (HTTP timeout option) --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ composer.json | 2 +- tests/FunctionalTest.php | 24 ++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 86bbbde..654f964 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ This project provides a *simple* API for invoking *async* RPCs to remote web ser * [Functions](#functions) * [Promises](#promises) * [Cancellation](#cancellation) + * [Timeouts](#timeouts) * [Install](#install) * [Tests](#tests) * [License](#license) @@ -325,6 +326,43 @@ $loop->addTimer(2.0, function () use ($promise) { }); ``` +#### Timeouts + +This library uses a very efficient HTTP implementation, so most SOAP requests +should usually be completed in mere milliseconds. However, when sending SOAP +requests over an unreliable network (the internet), there are a number of things +that can go wrong and may cause the request to fail after a time. As such, +timeouts are handled by the underlying HTTP library and this library respects +PHP's `default_socket_timeout` setting (default 60s) as a timeout for sending the +outgoing SOAP request and waiting for a successful response and will otherwise +cancel the pending request and reject its value with an Exception. + +Note that this timeout value covers creating the underlying transport connection, +sending the SOAP request, waiting for the remote service to process the request +and receiving the full SOAP response. To pass a custom timeout value, you can +assign the underlying [`timeout` option](https://github.com/clue/reactphp-buzz#timeouts) +like this: + +```php +$browser = new Browser($loop); +$browser = $browser->withOptions(array( + 'timeout' => 10.0 +)); + +$client = new Client($browser, $wsdl); +$proxy = new Proxy($client); + +$proxy->demo()->then(function ($response) { + // response received within 10 seconds maximum + var_dump($response); +}); +``` + +Similarly, you can use a negative timeout value to not apply a timeout at all +or use a `null` value to restore the default handling. Note that the underlying +connection may still impose a different timeout value. See also the underlying +[`timeout` option](https://github.com/clue/reactphp-buzz#timeouts) for more details. + ## Install The recommended way to install this library is [through Composer](https://getcomposer.org). diff --git a/composer.json b/composer.json index 33ea0da..3b7fc4a 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ }, "require": { "php": ">=5.3", - "clue/buzz-react": "^2.0 || ^1.3", + "clue/buzz-react": "^2.5", "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3", "react/promise": "^2.1 || ^1.2", "ext-soap": "*" diff --git a/tests/FunctionalTest.php b/tests/FunctionalTest.php index 8190a2f..9093088 100644 --- a/tests/FunctionalTest.php +++ b/tests/FunctionalTest.php @@ -141,9 +141,10 @@ public function testBlzServiceWithInvalidMethod() } /** - * @expectedException Exception + * @expectedException RuntimeException + * @expectedExceptionMessage cancelled */ - public function testCancelMethodRejects() + public function testCancelMethodRejectsWithRuntimeException() { $api = new Proxy($this->client); @@ -153,6 +154,25 @@ public function testCancelMethodRejects() Block\await($promise, $this->loop); } + /** + * @expectedException RuntimeException + * @expectedExceptionMessage timed out + */ + public function testTimeoutRejectsWithRuntimeException() + { + $browser = new Browser($this->loop); + $browser = $browser->withOptions(array( + 'timeout' => 0 + )); + + $this->client = new Client($browser, self::$wsdl); + $api = new Proxy($this->client); + + $promise = $api->getBank(array('blz' => '12070000')); + + Block\await($promise, $this->loop); + } + public function testGetLocationForFunctionName() { $this->assertEquals('http://www.thomas-bayer.com/axis2/services/BLZService', $this->client->getLocation('getBank'));