处理请求池中的异常 [英] Handling exceptions on a Pool of Requests

查看:68
本文介绍了处理请求池中的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆