Skip to content

feat(bigtable): modularize channel priming behind a ChannelPrimer interface - #20027

Merged
sushanb merged 4 commits into
googleapis:mainfrom
sushanb:feat/bigtable-channel-primer
Jun 23, 2026
Merged

feat(bigtable): modularize channel priming behind a ChannelPrimer interface#20027
sushanb merged 4 commits into
googleapis:mainfrom
sushanb:feat/bigtable-channel-primer

Conversation

@sushanb

@sushanb sushanb commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Mirrors the pluggable shape that PR #19987 established for the Direct Access compatibility check. Channel priming had been hard-wired into the pool via three loose options (WithInstanceName / WithAppProfile / WithFeatureFlagsMetadata) that the connectionFactory had to stitch back together on every dial.

  • New ChannelPrimer interface (channel_primer.go): Prime(ctx, *BigtableConn) error. The pluggable extension point that future pool factories (session-based, custom) can swap in.
  • pingAndWarmChannelPrimer is today's only implementation; it owns the (instance, appProfile, featureFlagsMD) tuple and delegates to BigtableConn.Prime — the existing PingAndWarm RPC stays untouched.
  • New WithChannelPrimer pool option replaces WithInstanceName / WithAppProfile / WithFeatureFlagsMetadata.
  • connectionFactory now carries a ChannelPrimer instead of three individual fields. When the primer is nil, primeWithRetry returns immediately — the pool dials the channel and puts it straight into rotation, no PingAndWarm sent. The classic channel pool factory still wires the pingAndWarmChannelPrimer, so user-facing default behavior is unchanged.
  • pingAndWarmDirectAccessChecker reuses the same primer rather than duplicating conn.Prime(ctx, instance, profile, flags) in two places. The factory now constructs one primer and shares it with both the pool (via WithChannelPrimer) and the checker, eliminating the three-arg drift that existed across the two consumers.

Test plan

  • go build ./... clean
  • go vet ./... clean
  • golint clean on touched files
  • go test ./internal/transport/... passes (existing tests migrated; new channel_primer_test.go covers (a) pingAndWarmChannelPrimer.Prime issues PingAndWarm carrying the configured feature-flag metadata, and (b) connectionFactory skips priming entirely when the primer is nil)

…erface

Mirrors the pluggable shape PR googleapis#19987 established for the Direct Access
compatibility check. Channel priming had been hard-wired into the pool
via three loose options (WithInstanceName / WithAppProfile /
WithFeatureFlagsMetadata) that the connectionFactory had to stitch back
together on every dial. Modularize:

- New ChannelPrimer interface in channel_primer.go with method
  Prime(ctx, *BigtableConn) error. The pluggable extension point that
  future pool factories (session-based, custom) can swap in.
- pingAndWarmChannelPrimer is today's only implementation; it owns the
  (instance, appProfile, featureFlagsMD) tuple and delegates to
  BigtableConn.Prime — the existing PingAndWarm RPC stays untouched.
- WithChannelPrimer pool option replaces WithInstanceName /
  WithAppProfile / WithFeatureFlagsMetadata.
- connectionFactory now carries a ChannelPrimer instead of three
  individual fields. When the primer is nil, primeWithRetry returns
  immediately — the pool dials the channel and puts it straight into
  rotation, no PingAndWarm sent. Existing factories opt in by passing
  WithChannelPrimer; the user-facing default behaviour (classic channel
  pool factory) is unchanged because it always wires the
  pingAndWarmChannelPrimer.
- pingAndWarmDirectAccessChecker reuses the same primer rather than
  duplicating conn.Prime(ctx, instance, profile, flags) in two places.
  The factory now constructs one primer and shares it with both the
  pool (via WithChannelPrimer) and the checker, eliminating the
  three-arg drift that existed across the two consumers.

Tests:
- channel_primer_test.go: pingAndWarmChannelPrimer.Prime issues
  PingAndWarm carrying the configured feature-flag metadata, and
  connectionFactory skips priming entirely when primer is nil.
- Existing connpool tests migrated to the new options / factory field.
@sushanb
sushanb requested review from a team as code owners June 19, 2026 07:37
@product-auto-label product-auto-label Bot added the api: bigtable Issues related to the Bigtable API. label Jun 19, 2026

@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 pluggable ChannelPrimer interface to decouple the channel warming strategy from the connection pool and direct-access checker. By encapsulating the priming parameters (instance name, app profile, and feature flags) into a single pingAndWarmChannelPrimer implementation, it simplifies the configuration and prevents parameter drift. The feedback suggests further improving this decoupling by using the ChannelPrimer interface type instead of the concrete *pingAndWarmChannelPrimer struct within the pingAndWarmDirectAccessChecker struct and constructor.

Comment thread bigtable/internal/transport/direct_access_checker.go
…cker

Accept the interface instead of the concrete *pingAndWarmChannelPrimer
so the checker no longer pins a specific priming implementation. Existing
call sites already pass *pingAndWarmChannelPrimer, which satisfies the
interface — no functional change.

Addresses gemini-code-assist feedback on PR googleapis#20027.
// factory uses, so the exact PingAndWarm invocation (instance name, app
// profile, feature-flag metadata) stays in one place — both the
// compatibility probe and any single-endpoint investigation go through it.
type pingAndWarmDirectAccessChecker struct {

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.

nit: maybe rename this to DirectAccessChecker? Cause the way it primes the channel depends on the ChannelPrimer which is just an interface and not necessarily being the PingAndWarmPrimer (even though that's the only implementation we have currently)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Renamed to directAccessChecker in 0750ee4 (constructor: newDirectAccessChecker). Kept it unexported — directAccessChecker (lowercase struct) can coexist with DirectAccessChecker (uppercase interface) in the same package, which is idiomatic Go for a private impl of a public interface. Also generalized the type doc comment so it no longer says "PingAndWarm" — that mechanism is now an implementation detail of the injected primer, and the interface doc still calls out the upcoming GetClientConfiguration-based checker for the session channel pool.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Walking this one back in 08aa124 — restored pingAndWarmDirectAccessChecker. Discussed with Sushan offline: the session channel pool will ship a sibling getClientConfigDirectAccessChecker that probes via GetClientConfiguration instead of PingAndWarm. With two impls, symmetric mechanism-naming prefixes read better than one generic name + one prefixed sibling. The "today's only impl" framing that justified dropping the prefix stops being true the moment that sibling lands. Sorry for the churn.

sushanb added 2 commits June 23, 2026 19:59
…cessChecker

The checker's probing behavior is now defined by the injected
ChannelPrimer rather than hard-wired to PingAndWarm, so the
pingAndWarm prefix on the type name no longer reflects what it does.
Drop the prefix; the only PingAndWarm-specific piece is the primer
implementation the factory passes in.
…directAccessChecker"

This reverts commit 0750ee4.

A second DirectAccessChecker impl is coming for the session channel
pool that probes via GetClientConfiguration. Once that lands, the two
impls read better with symmetric mechanism-naming prefixes
(pingAndWarmDirectAccessChecker / getClientConfigDirectAccessChecker)
than with one generic name and one prefixed sibling. Restore the
original name now to avoid having to rename twice.
@sushanb
sushanb merged commit 5214ab7 into googleapis:main Jun 23, 2026
19 checks passed
sushanb added a commit to sushanb/google-cloud-go that referenced this pull request Jun 23, 2026
Resolved conflict in bigtable/internal/transport/channel_pool_factory.go:
upstream PR googleapis#20027 replaced WithInstanceName / WithAppProfile /
WithFeatureFlagsMetadata with a single WithChannelPrimer option built
from a pingAndWarmChannelPrimer. Updated the basePoolOpts helper to
accept that primer (dropping the old three args) and updated
CreateSessionChannelPool to build its own primer the same way — the
session pool channels still use PingAndWarm for per-connection priming;
only the Direct Access compatibility decision moves to the
GetClientConfiguration-based checker.
sushanb added a commit to sushanb/google-cloud-go that referenced this pull request Jul 6, 2026
…erface (port of googleapis#20027)

Hand-port of upstream 5214ab7 into the sessionz branch. Cherry-pick
failed on layout drift for the same reason as PR googleapis#19987 — the top-level
bigtable/channel_pool_factory.go doesn't exist upstream — so the diff
was reproduced by hand.

Mirrors the pluggable shape that the DAC extract established:

- New internal/transport/channel_primer.go: ChannelPrimer interface with
  a single Prime(ctx, *BigtableConn) error method. Today's default
  implementation, pingAndWarmChannelPrimer, owns the (instance name,
  app profile, feature-flag metadata) tuple and delegates to
  BigtableConn.Prime. Constructor exported as NewPingAndWarmChannelPrimer
  so the top-level bigtable package can wire it.
- New internal/transport/channel_primer_test.go: covers (a) primer
  delegates PingAndWarm with configured feature-flag metadata,
  (b) connectionFactory skips priming entirely when primer is nil.
- connpool.go: add WithChannelPrimer option and channelPrimer field on
  BigtableChannelPool. Drop WithFeatureFlagsMetadata and the featureFlagsMD
  field. Keep WithInstanceName / WithAppProfile — the sessionz
  ChannelPoolSnapshot still reads them for debugview channelz/configz
  identity. connectionFactory now carries a ChannelPrimer instead of
  three individual fields; primeWithRetry returns immediately when the
  primer is nil so the pool can be used without priming.
- direct_access_checker.go: pingAndWarmDirectAccessChecker now takes a
  ChannelPrimer instead of (instance, appProfile, featureFlagsMD) — both
  CheckCompatibility and probeSingleEndpoint route their Prime through
  it. NewPingAndWarmDirectAccessChecker signature updated accordingly.
- bigtable/channel_pool_factory.go: construct one ChannelPrimer and
  share it with both the pool (via WithChannelPrimer) and the checker,
  eliminating the three-arg drift between them.

Test updates in connpool_test.go: poolOpts() adds the primer,
NilDirectAccessChecker case takes a primer to isolate the checker gate,
TestConnectionFactory factory struct uses the primer field, and the
five TestDirectAccessLogic subtests construct a primer for their DA
checker.

Verified: go build ./... , go vet ./... , and
go test ./internal/transport/... ./debugview/ -count=1 -short all pass.
sushanb added a commit to sushanb/google-cloud-go that referenced this pull request Jul 7, 2026
Take upstream/main's versions of both files. Fork's ports of googleapis#20027
and googleapis#19987 exported the constructors (NewPingAndWarm...) and made
them return interfaces; upstream landed them unexported (newPingAndWarm...)
returning concrete types. Upstream's channel_pool_factory.go calls the
unexported forms, so restoring these files re-aligns the trio.

Downstream break to fix next: fork's internal/session and
internal/transport/session_* code that called the uppercase exported
constructors will now need to be updated to the unexported forms or
to route through the interface accessors upstream provides.
sushanb added a commit to sushanb/google-cloud-go that referenced this pull request Jul 10, 2026
Restructures the spec-driven review deck from a 5-slide feature tour
into a 4-slide 'why we moved from one-shot prompting to specs' story:

- Slide 1 — one-shot prompting definition + the three PRs that shipped
  this way (googleapis#19987 DirectAccessChecker, googleapis#20027 ChannelPrimer, googleapis#20099
  client-side-metrics decouple). Common shape: extract one implicitly-
  unary abstraction into an interface.
- Slide 2 — Jetstream is 30k+ LOC; one-shot breaks. Introduces the five
  spec files with verified invariant counts (10 / 4 / 5 / 3 / 12+PartC)
  and one illustrative rule per spec.
- Slide 3 — SESSION_COMPONENT_SPEC.md tour: Part A (7-layer descriptive
  map), Part B (12 boundary MUST-rules with grep patterns), Part C
  (ownership matrix excerpts).
- Slide 4 — three prompt sizes with real examples from this branch:
  (1) simple refactor — activeVRPC/casActiveVRPC accessor extraction;
  (2) logic addition — adaptive session-creation throttler + how the
  spec invariants (POOL #5, CLIENT #3, B6) chain together;
  (3) big feature — unified debugview/ (7 z-pages behind one Handler)
  and how B3, POOL #4, B10 crystallized during that refactor.
  Plus reviewer-agent flow and PASS/VIOLATION/AMBIGUOUS semantics.

CSS and navigation unchanged. Counter reflects 4 slides. Companion
specs-deck.md not updated in this commit — will follow.
hongalex pushed a commit that referenced this pull request Jul 23, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.51.0](bigtable/v1.50.0...bigtable/v1.51.0)
(2026-07-23)


### Features

* **bigtable:** Add ChainInterceptors and RetryingVRpc for vRPC pipeline
([#20185](#20185))
([c7a832a](c7a832a))
* **bigtable:** Add ClientConfigurationManager
([#19986](#19986))
([3a8f927](3a8f927))
* **bigtable:** Add debug tag counter (recordDebugTag / assertDebugTag)
([#20114](#20114))
([3c97590](3c97590))
* **bigtable:** Add lazyPool helper for on-demand session pool opening
([#20182](#20182))
([f6ae3fb](f6ae3fb))
* **bigtable:** Add PeakEwma continuous time-decay latency tracker
([#20187](#20187))
([9d124ef](9d124ef))
* **bigtable:** Add PoolSizer for server-driven session pool capacity
([#20189](#20189))
([57ebbeb](57ebbeb))
* **bigtable:** Add session package with SessionClient + SessionTableAPI
interfaces
([#20180](#20180))
([4b82fd2](4b82fd2))
* **bigtable:** Add Session primitives (AttemptOutcome, vRPC ctx,
msgtype)
([#20116](#20116))
([e1011e2](e1011e2))
* **bigtable:** Add Session state enum
([#19981](#19981))
([0748972](0748972))
* **bigtable:** Add SessionThrottler / AdaptiveSessionThrottler for
OpenSession pacing
([#20184](#20184))
([02e3c6d](02e3c6d))
* **bigtable:** Add SessionThrottler / AdaptiveSessionThrottler for
OpenSession pacing
([#20184](#20184))
([29be83e](29be83e))
* **bigtable:** Add sessionTracer for per-Session lifecycle + vRPC
metrics
([#20190](#20190))
([a466345](a466345))
* **bigtable:** Enable new auth library and JWT for instance admin
client
([#20013](#20013))
([21c4a44](21c4a44))
* **bigtable:** Modularize channel priming behind a ChannelPrimer
interface
([#20027](#20027))
([5214ab7](5214ab7))
* **bigtable:** Modularize Direct Access compatibility check
([#19987](#19987))
([a25e93d](a25e93d))
* **o11y:** Regenerate clients for LRO tracing
([#20107](#20107))
([779074e](779074e))


### Bug Fixes

* **bigtable:** Default cluster/zone in toOtelMetricAttrs to avoid
Monitoring reject
([#20178](#20178))
([14493f4](14493f4))
* **bigtable:** Eliminate stats-handler MD race in internal/metrics
tracer
([#20158](#20158))
([c387066](c387066))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: bigtable Issues related to the Bigtable API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants