fix: Share reqwest HTTP clients#2152
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
| static SYNC_CLIENT: OnceLock<reqwest::blocking::Client> = OnceLock::new(); | ||
| static SYNC_CLIENT_REDIRECTS: OnceLock<reqwest::blocking::Client> = OnceLock::new(); |
There was a problem hiding this comment.
IMO I prefer to not by default store global state like this. I'd rather the caller of the library chooses to store the HTTP client as global state if they'd like. I'm not sure if it has meaningful impact on memory/perf. I defer to @gpeacock on the final decision.
There was a problem hiding this comment.
Normally, the client itself is stateless (it is not state that changes behavior). You are reusing HTTP plumbing, so you do not recreate it, with all the underlying plumbing and needed memory, on the flight, on each call you need it.
A new reqwest client goes through reqwest::new, which spawns a tokio runtime current thread on this thread, with its conenction pool.
Now imagine this in a server under load. N concurrent requests, each on its own worker thread, each going through this (and a few fetches), rebuilding on each call. Without sharing, every worker thread spawns its own runtime thread, and undergoes init again. (I don't think it impacts perf yet, but memory: threads do not come for free).
The caller could, choose, yes, but we also should have our default part reuse this for better defaults. The two statics only govern the default built-in resolver, where the library owns the lifecycle, not the caller. And the OnceLock is lazy, so if the network path is never touched, nothing is allocated.
There was a problem hiding this comment.
I think this is ok, but I'm nervous about it after the problems we had with settings that were held in a thread local
Changes in this pull request
Checklist
TO DOitems (or similar) have been entered as GitHub issues and the link to that issue has been included in a comment.