处理请求池中的异常 [英] Handling exceptions on a Pool of Requests
问题描述
我正在使用Guzzle将大量请求发送到API端点,并使用 Pool
功能异步并发发送这些请求.
I'm using Guzzle to send a number of requests to an API endpoint, using the Pool
functionality to send these asynchronously and concurrently.
脚本如下:
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\RequestException;
/* Configure logger */
Logger::configure("config/logger.xml");
$logger = Logger::getLogger("console");
/* Configure Guzzle Client */
$client = new Client([
'base_uri' => 'http://my.api/',
'timeout' => 2.0,
'allow_redirects' => false,
]);
/* Anonymous function (closure) to 'yield' X number of Requests */
$requests = function ($num_requests) {
for ($i = 0; $i < $num_requests; $i++) {
yield new Request('GET', "/MY_UNIQUE_IDENTIFIER/");
}
};
/* Create a Pool for the above requests */
$pool = new Pool($client, $requests(20), [
'concurrency' => 5, // Determine how many requests to send concurrently
'fulfilled' => function ($response, $index) {
$logger->info('$index: ' . $index . ', $response: ' . $response);
},
'rejected' => function ($reason, $index) {
try {
echo $reason;
} catch (\Exception $e) {
trigger_error($e->getMessage(), E_USER_WARNING);
}
},
]);
/* Initiate transfers/create a promise */
$promise = $pool->promise();
/* Force the pool of requests to complete */
$promise->wait();
基本上,将20个请求(一次5个)发送到 http://my.api/MY_UNIQUE_IDENTIFIER
.
Basically, send 20 requests (5 at a time) to http://my.api/MY_UNIQUE_IDENTIFIER
.
Pool
似乎可以使用.如果将 echo
添加到 rejected
请求中,则会得到如下输出:
The Pool
appears to work. If I add an echo
to the rejected
requests, I get output like:
#0 /Users/me/guzzle-POC/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(149): GuzzleHttp\Handler\CurlFactory::createRejection(Object(GuzzleHttp\Handler\EasyHandle), Array)
#1 /Users/me/guzzle-POC/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(102): GuzzleHttp\Handler\CurlFactory::finishError(Object(GuzzleHttp\Handler\CurlMultiHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#2 /Users/me/guzzle-POC/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(181): GuzzleHttp\Handler\CurlFactory::finish(Object(GuzzleHttp\Handler\CurlMultiHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#3 /Users/me/guzzle-POC/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(110): GuzzleHttp\Handler\CurlMultiHandler->processMessages()
#4 /Users/me/guzzle-POC/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(125): GuzzleHttp\Handler\CurlMultiHandler->tick()
#5 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(246): GuzzleHttp\Handler\CurlMultiHandler->execute(true)
#6 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(223): GuzzleHttp\Promise\Promise->invokeWaitFn()
#7 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(267): GuzzleHttp\Promise\Promise->waitIfPending()
#8 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(225): GuzzleHttp\Promise\Promise->invokeWaitList()
#9 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#10 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/EachPromise.php(101): GuzzleHttp\Promise\Promise->wait()
#11 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(246): GuzzleHttp\Promise\EachPromise->GuzzleHttp\Promise\{closure}(true)
#12 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(223): GuzzleHttp\Promise\Promise->invokeWaitFn()
#13 /Users/me/guzzle-POC/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#14 /Users/me/guzzle-POC/poc.php(50): GuzzleHttp\Promise\Promise->wait()
#15 {main}GuzzleHttp\Exception\ConnectException: cURL error 6: Could not resolve host: my.api (see http://curl.haxx.se/libcurl/c/libcurl-errors.html) in /Users/me/guzzle-POC/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:185
这里的主要问题是#15
,无法解析主机:my.api
.这是预期的行为,但是我想捕获此异常.
The main problem here being #15
, Could not resolve host: my.api
. This is expected behaviour, but I want to catch this exception.
我使用的 try/catch
根本不起作用-它什么也没抓住.
The try/catch
that I've used just doesn't work at all - it catches nothing.
大概是由于Pool的异步特性,但是有可能以任何方式捕获这些异常吗?
Presumably this is because of the Pool's asynchronous nature, but is it possible to catch these exceptions in any way?
我基本上想要实现的是,如果无法解决;记录错误并继续其他请求
类型的方法.
All I want to achieve basically is, if can't resolve; log error and continue with other requests
-type approach.
推荐答案
我有一个类似的问题,我将分享一个对我有用的解决方案.
以您的问题为例,
I had a similar problem, I would share a solution which worked for me.
Taking example from your question,
这是给出枪口异常的树层次结构的图片(来源:枪口文档).
如果发生网络错误,还会抛出 GuzzleHttp \ Exception \ ConnectException
异常,并且 ConnectException
没有相关的响应,因此存在没有400或500错误.因此,它应该为 hasResponse()
This is the picture which gives the tree heirarchy of guzzle exception(source Guzzle Docs.)
Also GuzzleHttp\Exception\ConnectException
exception is thrown in the event of a networking error and also ConnectException
does not have an associated response, so therefore there is no 400 or 500 error. So it should give false for hasResponse()
$client = new Client([
'base_uri' => 'http://my.api/',
'timeout' => 2.0,
'allow_redirects' => false,
]);
/* Anonymous function (closure) to 'yield' X number of Requests */
$requests = function ($num_requests) {
for ($i = 0; $i < $num_requests; $i++) {
yield new Request('GET', "/MY_UNIQUE_IDENTIFIER/");
}
};
/* Create a Pool for the above requests */
$pool = new Pool($client, $requests(20), [
'concurrency' => 5, // Determine how many requests to send concurrently
'fulfilled' => function ($response, $index) {
$logger->info('$index: ' . $index . ', $response: ' . $response);
},
'rejected' => function (\GuzzleHttp\Exception\TransferException $reason, $index) {
if ($reason->hasResponse()){
// this will mainly catch RequestException(Exception with statuscode and responses)
if ($reason->getResponse()->getStatusCode() == '400') {
// log your exception
} elseif($reason->getResponse()->getStatusCode() == '403'){
//log your unauthorised code exception
}else{
//similarly log your other status code exception
}
} else{
// ConnectException should come here, you can log it, will not have any responses as the request was never sent.
}
},
]);
/* Initiate transfers/create a promise */
$promise = $pool->promise();
/* Force the pool of requests to complete */
$promise->wait();
缺点
您需要知道异常的确切状态代码.
Demerits
You need to know the exact status code of your exceptions.
此外,如果特定于某人只捕获ServerException或ClientException,那么他们可以在层次结构树中将TransferException替换为其他异常.
Also if someone is specific to only catch ServerException or ClientException, then they can replace TransferException with other exception down the heirarchy tree.
'rejected' => function (\GuzzleHttp\Exception\RequestException $reason, $index) {
这篇关于处理请求池中的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!