Skip to content

fix(firestore): use pooled HTTP/2 connections by default to fix slow/failing concurrent requests - #305

Merged
demolaf merged 12 commits into
mainfrom
firestore/http2-pooled-client
Sep 21, 2026
Merged

demolaf merged 12 commits into
mainfrom
firestore/http2-pooled-client

Conversation

@demolaf

@demolaf demolaf commented Jul 23, 2026 •

Copy link
Copy Markdown
Member

Fixes #297.

Dart's Firestore client used dart:io's HttpClient, which only speaks HTTP/1.1, so every concurrent request opened its own TCP+TLS connection. At high concurrency this caused connection-storm failures (ClientException, HandshakeException) and made Dart much slower than Node, whose Firestore client multiplexes concurrent operations over a small pool of HTTP/2 connections.

Firestore traffic now goes over package:http2's Http2Client, which packs requests onto shared connections under a 100-stream cap and dials another once those fill. It speaks only HTTP/2, so a small wrapper keeps the endpoints that are still plain HTTP on HTTP/1.1: the emulator, Settings.ssl: false, and the credential sources googleapis_auth reaches through the same base client, such as the GCE metadata server.

Benchmark

Concurrency Run 1 Run 2 Run 3
3000 2438.35ms 1602.67ms 1245.91ms
5000 2460.53ms 2199.92ms 2111.67ms
10000 7195.02ms 1518.93ms 2180.65ms

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a custom HTTP/2 client pool (Http2ClientPool) to multiplex Firestore requests over shared HTTP/2 connections in production, bringing the Dart SDK closer to the Node.js implementation. While the addition of HTTP/2 support is a great performance improvement, several critical issues were identified in the review: HTTP/2 header keys must be lowercased to prevent protocol errors; the statusCompleter and bodyController must be properly closed on stream completion or error to prevent hanging requests; socket leaks must be avoided by destroying the socket if HTTP/2 negotiation fails; and failed connections must be cleaned up from the pool to prevent memory leaks.

@demolaf
demolaf marked this pull request as draft July 23, 2026 12:51
@demolaf demolaf changed the title Firestore/http2 pooled client fix(firestore): use pooled HTTP/2 connections by default to fix slow/failing concurrent requests Jul 23, 2026
@demolaf
demolaf marked this pull request as ready for review July 23, 2026 16:06
@demolaf

demolaf commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces HTTP/2 connection pooling by default for the Firestore client to address slow and failing requests under high concurrency. It implements a custom ClientPool and Http2ClientPool to manage and reuse HTTP/2 connections, and adds corresponding unit tests. The reviewer provided several actionable suggestions to improve robustness and performance: linking the cancellation of the response stream to the underlying HTTP/2 stream subscription to prevent resource leaks, wrapping resource cleanup in a try-catch block to handle failures safely, running connection collection unawaited to avoid adding latency to requests, and properly awaiting the termination of the connection pool during client shutdown to prevent hangs.

@demolaf
demolaf requested a review from brianquinlan July 23, 2026 16:51
@demolaf
demolaf changed the base branch from main to fix/ci-codecov-action-allowlist July 23, 2026 17:23
@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Coverage Report

✅ Coverage 74.12% meets 40% threshold

Total Coverage: 74.12%
Lines Covered: 5993/8085

Package Breakdown

Package Coverage
google_cloud_firestore 74.74%
firebase_admin_sdk 73.42%

Minimum threshold: 40%

@brianquinlan

Copy link
Copy Markdown
Contributor

@demolaf

Would it make sense for the Client interface to live in package:http2?

@demolaf

demolaf commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

@brianquinlan this makes sense, do we land this first and open a new issue/PR on dart-lang/http repo or vice versa?

@brianquinlan

Copy link
Copy Markdown
Contributor

I would love to see a PR on the dart-lang/http repo. I'm going to be out next week so maybe @natebosch can review

Base automatically changed from fix/ci-codecov-action-allowlist to main July 31, 2026 10:45
@demolaf
demolaf force-pushed the firestore/http2-pooled-client branch from 92ae533 to 38d8a53 Compare September 18, 2026 12:27
@demolaf
demolaf force-pushed the firestore/http2-pooled-client branch from 04e6768 to b752016 Compare September 18, 2026 13:17
@demolaf
demolaf requested a review from Lyokone September 21, 2026 08:58
@demolaf
demolaf merged commit 716f4a6 into main Sep 21, 2026
22 checks passed
@demolaf
demolaf deleted the firestore/http2-pooled-client branch September 21, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Concurrent request execution is exponentially slow

3 participants