Skip to content
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

[HttpClient] Lazily initialize CurlClientState #54207

Merged
merged 1 commit into from Mar 12, 2024

Conversation

arjenm
Copy link
Contributor

@arjenm arjenm commented Mar 8, 2024

Q A
Branch? 5.4
Bug fix? yes
New feature? no
Deprecations? no
Issues See below
License MIT

We have a dependency that recently started requiring symfony/http-client. Once that happened, our testing pipeline started to fail.

The failure turned out to be running out of open file descriptors.

It took a while to pinpoint the cause, but we identified the constructor of CurlClientState, specifically the curl_multi_init call in it, to cause an ever increasing number of open files (specifically, unix streams).

In our platform, we don't actually use HttpClient. But several services in Symfony have an "optional" dependency on it. Our examples were the TransportFactory-classes in the Mailer-package (including that for the NullTransport used in our testing pipeline) and the JsonManifestVersionStrategy.

I.e. as soon as the http-client package was installed, any time those services where requested, the container now first had to create the HttpClient-service. Which then selected CurlHttpClient as the best option. Which constructed its CurlClientState. And that in turn preemptively opened that stream.

We trigger the Mailer-service for every test, and given our 11k+ tests, that happened a lot of times. And apparently, the streams didn't get closed properly since we ran out of file descriptors after something like 9k tests done...

Unfortunately I was unable to create an isolated reproducer. My guess is that the reproducer was so much smaller, that PHP's memory cleanup could keep up and quickly identify and close abandoned resources (like the curl multihandle), whereas it could not in our much bigger application. But the issue (lots of 'STREAM' rows in the output of netstat or lsof) did not appear when an 'early return' was added to the CurlClientState's constructor (or when we explicitly specified null as httpclient for the mailer and our JsonManifestVersionStrategy).

This PR delays the (imo very heavy) construction of CurlClientState (including the initial reset) in CurlHttpClient to be a "just in time" occurrence.

@carsonbot carsonbot added this to the 7.1 milestone Mar 8, 2024
@arjenm arjenm changed the base branch from 7.1 to 6.4 March 8, 2024 15:23
@nicolas-grekas nicolas-grekas modified the milestones: 7.1, 6.4 Mar 8, 2024
@symfony symfony deleted a comment from carsonbot Mar 8, 2024
@carsonbot carsonbot changed the title Lazily initialize CurlClientState [HttpClient] Lazily initialize CurlClientState Mar 8, 2024
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, thanks for the explanations.

@fabpot
Copy link
Member

fabpot commented Mar 9, 2024

Don't we have the same issue in 5.4?

@arjenm
Copy link
Contributor Author

arjenm commented Mar 9, 2024

@fabpot if this code is in 5.4, than probably. I'm not sure if the fixes are valid php 7.x though.

@nicolas-grekas
Copy link
Member

Thank you @arjenm.

@nicolas-grekas nicolas-grekas merged commit 0a7825b into symfony:5.4 Mar 12, 2024
6 of 12 checks passed
This was referenced Apr 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants