Skip to content

feat: send HTTP/2 PING keepalives on the Bedrock provider - #5213

Open
jeremym-tanium wants to merge 4 commits into
maximhq:devfrom
jeremym-tanium:feat/bedrock-http2-keepalive
Open

feat: send HTTP/2 PING keepalives on the Bedrock provider#5213
jeremym-tanium wants to merge 4 commits into
maximhq:devfrom
jeremym-tanium:feat/bedrock-http2-keepalive

Conversation

@jeremym-tanium

@jeremym-tanium jeremym-tanium commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

When a Bedrock stream goes silent for tens of seconds (model "thinking"), an intermediary (reverse proxy / load balancer / service mesh) with an idle timeout shorter than the gap can sever the connection, surfacing as io.ErrUnexpectedEOF. This adds client-initiated HTTP/2 PING keepalives on the Bedrock provider transport so a quiet stream stays warm.

Changes

  • core/providers/bedrock/bedrock.go: when network_config.enforce_http2 is set and a positive http2_ping_interval_in_seconds is configured, set the transport's http.HTTP2Config{SendPingTimeout} (Go 1.24+ stdlib) to send a PING after that idle interval. Off by default (no ping) to keep enforce_http2 orthogonal to keepalive.
  • core/schemas/provider.go: add http2_ping_interval_in_seconds to NetworkConfig (opt-in; 0 = disabled, matching net/http's own SendPingTimeout semantics; mirrored in the Marshal/Unmarshal aliases).
  • core/schemas/serialization_test.go: unit test for the field round-trip + opt-in (0 = off) behavior.

Type of change

  • New feature (non-breaking)

How to test

cd core && go test ./schemas/ -run TestNetworkConfig_HTTP2PingInterval -count=1. Also validated end-to-end against real Bedrock behind an intermediary with a short idle timeout: HTTP/2 negotiated, PING frames emitted at the interval, stream survives a long thinking gap.

Affected areas

core / providers / bedrock; core / schemas

Breaking changes

None — gated on the existing enforce_http2 flag; default off.

Related issues

Closes #5211

Security considerations

None.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added opt-in HTTP/2 keepalive PING support for the Bedrock provider via http2_ping_interval_in_seconds (use 0 to disable; applies only when enforce_http2 is enabled).
  • Documentation
    • Updated config schemas, Helm values, and the provider UI form to expose http2_ping_interval_in_seconds.
    • Enhanced matview_refresh_interval to support disabling via off or 0s.
    • Updated the changelog to document the new keepalive behavior.
  • Tests
    • Added coverage for JSON round-tripping and defaulting of http2_ping_interval_in_seconds.

Walkthrough

Adds an optional HTTP/2 PING interval to Bedrock network configuration. The interval is serialized, schema-validated, tested, and applied to the Bedrock transport only when HTTP/2 is enforced and the interval is positive. Frontend schemas and types now represent the setting. Materialized-view interval validation also supports explicit disabling.

Changes

Bedrock HTTP/2 keepalive

Layer / File(s) Summary
Network configuration and validation
core/schemas/provider.go, core/schemas/serialization_test.go, transports/config.schema.json, helm-charts/bifrost/values.schema.json, ui/lib/schemas/providerForm.ts, ui/lib/types/config.ts, ui/lib/types/schemas.ts
Adds and round-trips the interval, validates its range, documents HTTP/2-only behavior, and tests serialization and defaults.
Bedrock transport keepalive wiring
core/providers/bedrock/bedrock.go, core/changelog.md
Sets SendPingTimeout for positive intervals with enforced HTTP/2 and documents the feature.

Materialized-view interval schema

Layer / File(s) Summary
Refresh interval validation
transports/config.schema.json
Allows off and zero durations, and documents clamping positive values below five seconds.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • #5010 — Both changes add configurable keepalive settings, although this PR targets Bedrock HTTP/2 PINGs while #5010 targets server-side SSE heartbeats.

Suggested reviewers: akshaydeo, bearts, pratham-mishra04, tejasghatte

Sequence Diagram(s)

sequenceDiagram
  participant NetworkConfig
  participant NewBedrockProvider
  participant HTTP2Transport
  participant Intermediary
  NetworkConfig->>NewBedrockProvider: HTTP2PingIntervalInSeconds
  NewBedrockProvider->>HTTP2Transport: configure SendPingTimeout
  HTTP2Transport->>Intermediary: send HTTP/2 PING
  Intermediary-->>HTTP2Transport: acknowledge HTTP/2 PING
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main Bedrock HTTP/2 keepalive feature.
Description check ✅ Passed The PR description follows the template well and includes summary, changes, testing, scope, breaking changes, related issues, and security notes.
Linked Issues check ✅ Passed The changes address #5211 by adding opt-in HTTP/2 PING keepalives to keep Bedrock streams alive during silent gaps.
Out of Scope Changes check ✅ Passed The modified files align with the Bedrock keepalive feature and its supporting schemas, tests, UI types, and docs.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai
coderabbitai Bot requested a review from akshaydeo July 14, 2026 21:49
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
core/providers/bedrock/bedrock.go Adds Bedrock HTTP/2 PING configuration when HTTP/2 is enforced and a positive interval is configured.
core/schemas/provider.go Adds the new network config field and includes it in custom JSON serialization.
core/schemas/serialization_test.go Adds coverage for the new field's JSON round trip and default behavior.
transports/config.schema.json Adds the new network config field to the main config schema definitions.
helm-charts/bifrost/values.schema.json Adds the new network config field to the Helm values schema.

Reviews (8): Last reviewed commit: "fix: make Bedrock HTTP/2 keepalive ping ..." | Re-trigger Greptile

Comment thread core/schemas/provider.go Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 14, 2026
@jeremym-tanium

Copy link
Copy Markdown
Contributor Author

Addressed the schema finding: added http2_ping_interval_in_seconds to the network_config block(s) in transports/config.schema.json, so a config.json that sets it is no longer rejected. Thanks for the catch.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 14, 2026
Comment thread transports/config.schema.json
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 14, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 14, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 14, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 15, 2026
@jeremym-tanium

Copy link
Copy Markdown
Contributor Author

Question for Bifrost devs:

Initially when I created the PR, I enabled the HTTP/2 PING keepalives by default with a reasonable interval, but I backed off that to preserve the current behavior but allowed configurability. The downside of that though is that other users could potentially experience these expected EOF stream timeout errors, debug, and then discover that there's a config knob. Would you prefer enabling these keepalives by default?

@jeremym-tanium

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest dev to clear the merge conflict. No functional change; the changelog entry moves to the end of the feat group and now sits alongside the current entries. go build ./... and the core/schemas serialization tests pass locally.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 21, 2026
@jeremym-tanium

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest dev to clear the merge conflict. dev's changelog was reorganized since the last push, so the keepalive entry now sits at the end of the feat group in the current list; no functional change. go build ./... and the core/schemas serialization tests pass locally.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 21, 2026
@jeremym-tanium

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest dev to clear the merge conflict. dev's core/changelog.md was reset by the v1.6.5 release cut, so the keepalive entry is now the first line of the next release's changelog. No functional change; build and core/schemas tests pass locally.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 21, 2026
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review July 24, 2026 22:43

The merge-base changed after approval.

@CLAassistant

CLAassistant commented Jul 28, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@jeremym-tanium
jeremym-tanium force-pushed the feat/bedrock-http2-keepalive branch from 52eede6 to 7c4a867 Compare July 28, 2026 14:46
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 28, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 30, 2026
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review July 30, 2026 16:09

The merge-base changed after approval.

When enforce_http2 is set, configure http.HTTP2Config.SendPingTimeout so the
client sends PING frames while a streaming or unary response is idle, keeping
a long-lived connection from being closed by an intermediary idle timeout
(which the AWS EventStream decoder would otherwise surface as an "unexpected
EOF"). The interval is configurable via network_config
http2_keepalive_interval_in_seconds (default 30s).
Mirror http2_ping_interval_in_seconds into the chart values.schema.json
networkConfig def so Helm deployments can set it.
There was no HTTP/2 ping keepalive before this change, so the 30s
default-fill was an arbitrary imposition. Treat 0 as disabled (matching
net/http's own SendPingTimeout semantics) and only send pings when a
positive interval is configured, keeping enforce_http2 orthogonal to
keepalive.
@jeremym-tanium
jeremym-tanium force-pushed the feat/bedrock-http2-keepalive branch from a7ac3d0 to bf89299 Compare July 30, 2026 19:19

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/bedrock/bedrock.go`:
- Around line 128-131: Update the UI NetworkConfig type in config.ts to declare
the http2_ping_interval_in_seconds property used by the Bedrock transport
configuration, with the appropriate numeric/optional contract so UI
serialization preserves the HTTP/2 keepalive value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 514a3de3-06cf-4bf4-aba7-663b70272b76

📥 Commits

Reviewing files that changed from the base of the PR and between a7ac3d0 and bf89299.

📒 Files selected for processing (6)
  • core/changelog.md
  • core/providers/bedrock/bedrock.go
  • core/schemas/provider.go
  • core/schemas/serialization_test.go
  • helm-charts/bifrost/values.schema.json
  • transports/config.schema.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • helm-charts/bifrost/values.schema.json
  • core/schemas/serialization_test.go

Comment thread core/providers/bedrock/bedrock.go
The TS NetworkConfig interface and its three Zod mirrors (providerForm's
NetworkConfigSchema, and schemas.ts's networkConfigSchema /
networkFormConfigSchema) were missing the field added alongside
enforce_http2 in the Go schema, so a value round-tripped through those
validators would be silently stripped.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/lib/schemas/providerForm.ts`:
- Line 46: Update the http2_ping_interval_in_seconds field in the provider form
schema to include the shared 3600-second maximum, preserving its integer,
non-negative, and optional constraints and using the same validation message as
the shared network schema.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a757472f-0479-4772-aaad-004e0ac04bef

📥 Commits

Reviewing files that changed from the base of the PR and between bf89299 and dee7dd3.

📒 Files selected for processing (3)
  • ui/lib/schemas/providerForm.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts

keep_alive_timeout_in_seconds: z.number().int().min(1).max(3600).optional(),
max_conns_per_host: z.number().int().min(1).max(10000).optional(),
enforce_http2: z.boolean().optional(),
http2_ping_interval_in_seconds: z.number().int().min(0).optional(),

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the provider-form bound consistent with the shared network schema.

This accepts any non-negative integer, while ui/lib/types/schemas.ts caps the same setting at 3600 seconds. Values above 3600 can therefore pass this schema but fail shared validation later. Add the same .max(3600, ...) constraint here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/lib/schemas/providerForm.ts` at line 46, Update the
http2_ping_interval_in_seconds field in the provider form schema to include the
shared 3600-second maximum, preserving its integer, non-negative, and optional
constraints and using the same validation message as the shared network schema.

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.

[Bug]: Bedrock streaming can drop with "unexpected EOF" when an intermediary idle timeout severs a quiet stream

4 participants