Skip to content

fix(chip-router): populate per-event PublishBatch results - #2861

Open
cawthorne wants to merge 1 commit into
mainfrom
fix/chip-router-per-event-publish-results
Open

cawthorne wants to merge 1 commit into
mainfrom
fix/chip-router-per-event-publish-results

Conversation

@cawthorne

Copy link
Copy Markdown
Contributor

Summary

PublishBatch always returned an empty PublishResponse regardless of the batch's outcome. The node-side batch client (chainlink-common/pkg/chipingress/batch) requires one PublishResult per event to resolve delivery: since chainlink-common#2326 (an audit remediation for a data-loss finding) an empty results array is reported to every event's callback as ErrCodeResultsMismatch.

Against this router, a chainlink v2.67.2-rc.0 node's durable emitter therefore treated every event as undelivered and retransmitted the whole stream every 60s, forever:

  • measured: 301,385 failed to deliver event. Relying on retransmit. warnings on a single node, first at 12s after boot, zero successful acks;
  • the Kafka topic filled with duplicate retransmits (~20x counter inflation, ~4k msg/s);
  • metric-event delivery latency gapped 1.5–4.5 min, breaking downstream freshness-gated consumers (CRE fire drills' time() - <metric>_ts < 120 gates).

The events were forwarded to Kafka on every attempt — only the acks were missing — so the storm duplicated the stream rather than losing data.

The fix

  • Ack each event (PublishResult{EventId}, nil error) when the batch was handed to at least one subscriber — the events were forwarded in that case, so the caller can resolve delivery and stop retransmitting.
  • Report a per-event PublishError when no subscriber accepted the batch, so the caller retains and retries (at-least-once preserved).
  • Return Unavailable when no subscribers are registered instead of an empty success — the previous behavior acked events that went nowhere, letting a durable store delete them undelivered (the exact data-loss shape flagged by the audit behind chainlink-common#2326).

Also bumps the module's chainlink-common/pkg/chipingress pin (Dec 2025 → Sep 2026): the old pin's pb predates PublishResult.Error.

Tests

New cmd/chip-router tests: per-event results with matching ids on a successful forward; Unavailable with no subscribers; per-event errors when every forward fails.

PublishBatch always returned an empty PublishResponse regardless of the
batch's outcome. The node-side batch client
(chainlink-common/pkg/chipingress/batch) requires one PublishResult per
event to resolve delivery: since chainlink-common#2326 an empty results
array is reported to every event's callback as ErrCodeResultsMismatch,
so a chainlink v2.67 node's durable emitter against this router treated
every event as undelivered and retransmitted the whole stream every 60s,
forever — measured at 301k 'failed to deliver event. Relying on
retransmit.' warnings on a single node within minutes of startup, a ~20x
duplicated Kafka topic, and metric delivery-latency gaps long enough to
break downstream freshness gates.

- Ack each event (PublishResult{EventId}, nil error) when the batch was
  handed to at least one subscriber; the events were forwarded in that
  case, so the caller can resolve delivery and stop retransmitting.
- Report a per-event PublishError when no subscriber accepted the batch,
  so the caller retains and retries (at-least-once preserved).
- Return Unavailable when no subscribers are registered instead of an
  empty success — the previous behavior acked events that went nowhere,
  letting a durable store delete them undelivered (the data-loss shape
  flagged by the audit behind chainlink-common#2326).

Bumps the module's chainlink-common/pkg/chipingress pin (Dec 2025 ->
Sep 2026) — the old pin's pb predates PublishResult.Error.
Copilot AI balanced review requested due to automatic review settings October 7, 2026 00:58
@cawthorne
cawthorne requested a review from a team as a code owner October 7, 2026 00:58
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

👋 cawthorne, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

📊 API Diff Results

No changes detected for module github.com/smartcontractkit/chainlink-testing-framework/framework/components/chiprouter

View full report

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Downstream per-event rejections and transactional forwarding failures can still be acknowledged as successful, risking data loss.

Review effort: Balanced
Findings: 2 High severity

Open (2)
What changed in this PR

Updates the chip router’s batch acknowledgements to stop unnecessary durable-emitter retransmissions while reporting forwarding failures.

Changes:

  • Returns per-event results and rejects batches when no subscribers exist.
  • Adds tests for successful forwarding and failure responses.
  • Updates ChipIngress, gRPC, and Go versions.
File Description
framework/​components/​chiprouter/​go.sum Updates dependency checksums.
framework/​components/​chiprouter/​go.mod Updates protocol dependencies and Go version.
framework/​components/​chiprouter/​cmd/​chip-router/​main.go Adds batch delivery results and failure handling.
framework/​components/​chiprouter/​cmd/​chip-router/​main_test.go Tests batch acknowledgements and forwarding failures.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +186 to +187
} else {
forwarded.Store(true)
}
results = append(results, result)
}
return &chippb.PublishResponse{Results: results}, nil

This branch has not been deployed

No deployments
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.

2 participants