使用池时如何修复 GuzzleHttp\Exception\ServerException?

How to fix GuzzleHttp\Exception\ServerException when using a Pool?

The docs 说我可以创建一个池,任何失败的请求都应该调用 "rejected" 方法,但我得到的是 GuzzleHttp\Exception\ServerException。这是我的代码:

$client = new GuzzleHttp\Client([
    'base_uri' => ServerConfig::Json('file_server'),
]);

$requests = function() use ($client, $delete_time) {
    foreach($this->pcs_master->pcs as $id => $pcs) {
        $paths = $pcs->database->SelectSimpleArray('wopi_doc', 'wd_filepath', ['wd_deleted_at IS NOT NULL', 'wd_deleted_at < ?' => $delete_time]);

        if ($paths) {
            foreach (array_chunk($paths, self::WOPI_SOFT_DELETE_CHUNK_SIZE) as $chunk) {
                yield $client->delete('/', [
                    'body' => json_encode(['paths' => $files]),
                ]);
            }
        }
    }
};

$pool = new GuzzleHttp\Pool($client, $requests(), [
    'concurrency' => self::WOPI_SOFT_DELETE_MAX_CONCURRENT_REQUESTS,
    'fulfilled' => function ($response, $index) {
        dump('fulfilled', $response, $index);
    },
    'rejected' => function ($reason, $index) {
        dump('rejected', $reason, $index);
    },
]);

$pool->promise()->wait();

例外情况:

TYPE: GuzzleHttp\Exception\ServerException
MESSAGE: Server error: 500
FILE: /path/to/my/project/vendor/guzzlehttp/guzzle/src/Middleware.php(68)
=== TRACE ===
#0 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(199): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response))
#1 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(152): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), Array)
#2 /path/to/my/project/vendor/guzzlehttp/promises/src/TaskQueue.php(60): GuzzleHttp\Promise\Promise::GuzzleHttp\Promise\{closure}()
#3 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(240): GuzzleHttp\Promise\TaskQueue->run(true)
#4 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(217): GuzzleHttp\Promise\Promise->invokeWaitFn()
#5 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(261): GuzzleHttp\Promise\Promise->waitIfPending()
#6 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(219): GuzzleHttp\Promise\Promise->invokeWaitList()
#7 /path/to/my/project/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#8 /path/to/my/project/vendor/guzzlehttp/guzzle/src/Client.php(129): GuzzleHttp\Promise\Promise->wait()
#9 /path/to/my/project/vendor/guzzlehttp/guzzle/src/Client.php(87): GuzzleHttp\Client->request('delete', '/', Array)
#10 /path/to/my/project/class/crondaemon.php(5057): GuzzleHttp\Client->__call('delete', Array)
#11 /path/to/my/project/class/crondaemon.php(5057): GuzzleHttp\Client->delete('/', Array)
#12 /path/to/my/project/vendor/guzzlehttp/guzzle/src/Pool.php(55): CronDaemon::{closure}()
#13 [internal function]: GuzzleHttp\Pool::GuzzleHttp\{closure}()
#14 /path/to/my/project/vendor/guzzlehttp/promises/src/EachPromise.php(73): Generator->rewind()
#15 /path/to/my/project/vendor/guzzlehttp/guzzle/src/Pool.php(74): GuzzleHttp\Promise\EachPromise->promise()
#16 /path/to/my/project/class/crondaemon.php(5073): GuzzleHttp\Pool->promise()
#17 [internal function]: CronDaemon->DeleteWopiDocs()
#18 /path/to/my/project/tests/cron.php(46): call_user_func(Array)
#19 /path/to/my/project/tests/cron.php(51): CronDaemonTestScript::main(Array)
#20 {main}

看起来 $client->delete 行抛出异常,但我认为应该创建一个 Request 对象但尚未发送(这是池的工作) ?

出于某种原因,我似乎必须将 Promise 包装在一个函数中:

foreach (array_chunk($paths, self::WOPI_SOFT_DELETE_CHUNK_SIZE) as $chunk) {
    yield function() use ($client, $files) {
        return $client->deleteAsync('/', [
            'body' => json_encode(['paths' => $files]),
        ]);
    };
}

client::get(), client::put(), client::post(), client::delete()client::request() 的抽象,它本身是 client::requestAsync(). 的抽象。您正试图生成一个 ResponseInterface 实例。 如果您打算使用 GuzzleHttp\Pool,则必须手动创建 Psr\http-message\Request 个对象。

yield new GuzzleHttp\Psr7\Request($method, $uri, $headers_array, $body, $protocol_version);

查看concurrent requests and GuzzleHttp\Psr7\Request

可获得更多信息

编辑:回复评论中的问题。 最终,您希望发送的每个请求都使用 Client::sendAsync() 发送。这意味着之前在客户端中配置的任何选项在池中使用时都将保持有效。