-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpClient] Fix Failed to open stream: Too many open files #45073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@nicolas-grekas I think the issue is related to $multi = (object) [
//'handle' => $this->handle,
//'handle' => &$this->handle,
'logger' => &$this->logger,
'pushedResponses' => &$this->pushedResponses,
'dnsCache' => &$this->dnsCache,
'handlesActivity' => &$this->handlesActivity,
'openHandles' => &$this->openHandles,
'execCounter' => &$this->execCounter,
'pauseExpiries' => &$this->pauseExpiries,
'lastTimeout' => &$this->lastTimeout,
];
// Keep a dummy "onPush" reference to work around a refcount bug in PHP
curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, $this->onPush = static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes) {
return self::handlePush($parent, $pushed, $requestHeaders, $multi, $maxPendingPushes);
}); It works. But I soon as I uncomment one of the One other thing I noticed, a lot more
var_dump($this->multi->handle); => . 854 / 4775 ( 17%)
resource(15232) of type (curl_multi)
.resource(15342) of type (curl_multi)
.resource(15383) of type (curl_multi)
var_dump($this->handle); => . 854 / 4775 ( 17%)
resource(26271) of type (curl_multi)
.resource(26500) of type (curl_multi)
.resource(26569) of type (curl_multi) |
@nicolas-grekas might have found a "leak" in if (\is_resource($this->handle) || $this->handle instanceof \CurlMultiHandle) {
if (\defined('CURLMOPT_PUSHFUNCTION')) {
curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, null);
}
$active = 0;
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->handle, $active));
}
foreach ($this->openHandles as [$ch]) {
if (\is_resource($ch) || $ch instanceof \CurlHandle) {
curl_setopt($ch, \CURLOPT_VERBOSE, false);
}
} If I add these 2 blocks (especially the one with the |
Regarding this part added in your last PR, I don't really understand the goal but shouldn't we have a call to $this->share = curl_share_init();
curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_DNS);
curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_SSL_SESSION);
if (\defined('CURL_LOCK_DATA_CONNECT')) {
curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_CONNECT);
} |
I wish I could reproduce locally. If you can share the code privately with me, you can reach me on Symfony's Slack. |
Can you please try this patch instead? --- a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php
+++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php
@@ -23,9 +23,9 @@ use Symfony\Component\HttpClient\Response\CurlResponse;
*/
final class CurlClientState extends ClientState
{
- /** @var \CurlMultiHandle|resource */
+ /** @var \CurlMultiHandle|resource|null */
public $handle;
- /** @var \CurlShareHandle|resource */
+ /** @var \CurlShareHandle|resource|null */
public $share;
/** @var PushedResponse[] */
public $pushedResponses = [];
@@ -65,8 +65,17 @@ final class CurlClientState extends ClientState
return;
}
- curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, function ($parent, $pushed, array $requestHeaders) use ($maxPendingPushes) {
- return $this->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes);
+ // Clone to prevent a circular reference
+ $multi = clone $this;
+ $multi->handle = null;
+ $multi->share = null;
+ $multi->pushedResponses = &$this->pushedResponses;
+ $multi->logger = &$this->logger;
+ $multi->handlesActivity = &$this->handlesActivity;
+ $multi->openHandles = &$this->openHandles;
+
+ curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes) {
+ return $multi->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes);
});
} |
a548fe5
to
40d22b8
Compare
Thanks @nicolas-grekas for the patch, it works perfectly, no more issues! 🚀 |
Thank you @adrienfr. |
With a large PHPUnit tests suite, I receive this error "Failed to open stream: Too many open files".
I found the original code from @nicolas-grekas here and with small adjustments, it resolves my issue.
Warning: tests for HttpClient are OK but would someone try with a real HTTP/2 client push? I was not able to test it.