Skip to content

feat(a2agrpc): add GRPCConnectionPool for gRPC client connection reuse (fixes #109) - #382

Open
kuangmi-bit wants to merge 2 commits into
a2aproject:mainfrom
kuangmi-bit:feat/grpc-connection-pool
Open

feat(a2agrpc): add GRPCConnectionPool for gRPC client connection reuse (fixes #109)#382
kuangmi-bit wants to merge 2 commits into
a2aproject:mainfrom
kuangmi-bit:feat/grpc-connection-pool

Conversation

@kuangmi-bit

Copy link
Copy Markdown
Contributor

Summary

Adds a GRPCConnectionPool interface and a default in-memory implementation that enables gRPC connection reuse across client creations. Fixes #109.

Problem

WithGRPCTransport calls grpc.NewClient(url, opts...) on every client creation. gRPC ClientConn is designed to be long-lived — it handles name resolution, TCP reconnection with backoff, and TLS handshakes. Creating one per call is wasteful, especially for integration patterns like ADK RemoteAgent where the constructor opens a connection on every invocation.

Solution

Adds two new exports to a2agrpc/v1:

1. GRPCConnectionPool interface

type GRPCConnectionPool interface {
    Acquire(ctx context.Context, url string, opts ...grpc.DialOption) (*grpc.ClientConn, error)
    Release(*grpc.ClientConn) error
}

2. DefaultGRPCConnectionPool

An in-memory pool keyed by URL with configurable idle TTL. Zero/negative TTL disables eviction.

pool := NewDefaultGRPCConnectionPool(5 * time.Minute)

3. WithPooledGRPCTransport

A FactoryOption that acquires from the pool and releases on Destroy():

pool := a2agrpc.NewDefaultGRPCConnectionPool(5 * time.Minute)
defer pool.Close()

client := a2aclient.NewFromCard(ctx, card,
    a2agrpc.WithPooledGRPCTransport(pool, grpc.WithTransportCredentials(...)),
)

Design decisions

  • Pool is explicit (WithPooledGRPCTransport) not implicit — users opt in
  • Accepts opts at Acquire time for consistency with WithGRPCTransport
  • TTL eviction runs on Acquire to avoid background goroutines
  • Release does NOT close the connection — the pool owns the lifecycle
  • 6 tests: acquire, reuse, multi-URL, TTL eviction, zero-TTL, release

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

Add a GRPCConnectionPool interface and a default in-memory
implementation for reusing gRPC connections by URL.

Background: grpc.NewClient creates a long-lived ClientConn with
name resolution, TCP reconnection, and TLS handshake. Creating
one per client (as the current WithGRPCTransport does) incurs
unnecessary overhead.

Changes:
- GRPCConnectionPool interface: Acquire(+opts), Release
- DefaultGRPCConnectionPool: in-memory pool with TTL eviction
- WithPooledGRPCTransport: FactoryOption that acquires from
  the pool and releases on transport Destroy
- 6 tests covering: acquire, reuse, multi-URL, TTL eviction,
  zero-TTL (no eviction), release semantics

Design follows yarolegovich's proposal in a2aproject#109.
@kuangmi-bit
kuangmi-bit force-pushed the feat/grpc-connection-pool branch from b3afd90 to e3776b9 Compare July 22, 2026 22:01
@kuangmi-bit

Copy link
Copy Markdown
Contributor Author

@nahapetyan-serob — gentle ping on this one too. CI is all green (Go + ITK + PR title).

This adds GRPCConnectionPool for gRPC client connection reuse (fixes #109). Each new connection currently pays the full TLS handshake cost — the pool amortizes this across calls. 34 tests, zero regressions.

Would appreciate a review when you have time.

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.

[Feature] Add an extension point for client connection pooling

1 participant