Skip to content

Add outbox-json protocol with per-row topic dispatch for Kafka sinks POC#4340

Open
benmeadowcroft wants to merge 14 commits intopingcap:masterfrom
benmeadowcroft:outbox-support
Open

Add outbox-json protocol with per-row topic dispatch for Kafka sinks POC#4340
benmeadowcroft wants to merge 14 commits intopingcap:masterfrom
benmeadowcroft:outbox-support

Conversation

@benmeadowcroft
Copy link

@benmeadowcroft benmeadowcroft commented Mar 3, 2026

What problem does this PR solve?

Issue Number: ref #4325

What is changed and how it works?

To support the transactional outbox pattern this PR adds support for defining outbox table(s) that define columns for the payload, keys, and headers of Kafka messages to send downstream when a new row is inserted into the outbox table.

Applications using the transactional outbox pattern write domain events to an outbox table in the same database transaction as the business change. TiCDC can then relay those events to a message broker using the application provided payload (this PR supports a JSON encoding specifically).

The other major change in this PR is per-row topic dispatch. This enables a single outbox table to have messages dispatched to different topics.

Tests

  • Unit test
  • Integration test

Questions

Will it cause performance regression or break compatibility?

The per-row topic dispatch is one potential area of concern. Previously the topic expressions could be calculated per table, now they may be done per row (to allow per-row topic dispatch). The PR does attempt to avoid this additional cost in the case that no column placeholders are included in the topic dispatch expression.

In terms of compatibility, the new configuration does add to the API surface area. I don't believe it breaks compatibliity, but will defer to reviewers insights on this.

Do you need to update user documentation, design documentation or monitoring documentation?

Yes, user documentation would need to be updated to include the additional configuration related to the new outbox-json protocol.

Release note

Support the outbox-json protocol and sink.outbox configuration for Kafka sinks so that TiCDC can publish one message per inserted outbox row, with configurable key/value columns, optional Kafka headers, and column-based topic dispatch, which simplifies implementing the transactional outbox pattern.

Summary by CodeRabbit

  • New Features

    • Added outbox-json sink support with configurable id/key/value columns, header-to-column mappings, encoder, and new outbox protocol.
    • Topic expressions can reference row columns; per-row dynamic topic dispatch and APIs to substitute/extract column placeholders.
    • Checkpoint broadcasts include discovered runtime row topics; message headers are emitted.
  • Bug Fixes / Validation

    • Validation tightened to reject sink/column-selector configs missing required outbox columns or invalid header mappings.
  • Tests

    • New unit and integration tests covering outbox encoding, headers, topic dispatch, column-selector, and checkpoint behavior.

Add protocol parse/string and sink.outbox validation.
Mirror outbox config in API v2 conversions.
Include protocol/config unit tests.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
Add {column:<name>} parsing and row-aware topic substitution.
Add DDL fallback/default-topic behavior for row-dependent rules.
Verify selector/topic/outbox required columns with tests.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
Resolve row topics after outbox eligibility filtering.
Track runtime discovered topics and include them in checkpoint fanout.
Add sink tests for checkpoint topic union behavior.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
Implement outbox encoder with one-row-per-message semantics.
Emit Id header first, then configured header mappings.
Wire message headers through Kafka producer and add tests.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
…alues, improved logs

Tracks use of column placeholders in expression once to avoid repeated expression evaluation
Replaced uses of `panic` with `log.Panic` and zap fields to align better with rest of the project.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
…h Kafka

The tests validate the basic protocol support, column topic expression handling, and kafka header support.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
The first draft of this codec includes fallback handling for DDL and Checkpoint events. We will instead explicitly ignore those operations in the current outbox codec.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
@ti-chi-bot ti-chi-bot bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. do-not-merge/needs-triage-completed labels Mar 3, 2026
@ti-chi-bot
Copy link

ti-chi-bot bot commented Mar 3, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign flowbehappy for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot bot added contribution This PR is from a community contributor. first-time-contributor Indicates that the PR was contributed by an external member and is a first-time contributor. needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. labels Mar 3, 2026
@ti-chi-bot
Copy link

ti-chi-bot bot commented Mar 3, 2026

Hi @benmeadowcroft. Thanks for your PR.

I'm waiting for a pingcap member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@ti-chi-bot
Copy link

ti-chi-bot bot commented Mar 3, 2026

Welcome @benmeadowcroft!

It looks like this is your first PR to pingcap/ticdc 🎉.

I'm the bot to help you request reviewers, add labels and more, See available commands.

We want to make sure your contribution gets all the attention it needs!



Thank you, and welcome to pingcap/ticdc. 😃

@pingcap-cla-assistant
Copy link

pingcap-cla-assistant bot commented Mar 3, 2026

CLA assistant check
All committers have signed the CLA.

@ti-chi-bot ti-chi-bot bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Mar 3, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances TiCDC's capabilities by introducing first-class support for the transactional outbox pattern. It allows for flexible configuration of Kafka message content, including keys, values, and headers, directly from database table columns. A major improvement is the introduction of per-row topic dispatch, enabling dynamic routing of messages to different Kafka topics based on data within each row. These changes empower users to implement more sophisticated event-driven architectures with TiCDC, while robust validation and checkpointing mechanisms ensure reliability.

Highlights

  • Transactional Outbox Pattern Support: Introduced a new outbox-json protocol for Kafka sinks, enabling TiCDC to support the transactional outbox pattern. This allows applications to write domain events to an outbox table within the same database transaction as business changes, with TiCDC relaying these events to a message broker.
  • Configurable Kafka Message Fields: Added OutboxConfig to allow users to define which columns from the outbox table should be used for the Kafka message ID, key, value, and optional headers. This provides flexibility in structuring the outgoing Kafka messages.
  • Per-Row Topic Dispatch: Implemented the ability to dispatch messages to different Kafka topics based on column values within each row. This is achieved through column placeholders in topic dispatch rules (e.g., {column:column_name}), allowing for dynamic topic routing.
  • Enhanced Configuration Validation: Added comprehensive validation for OutboxConfig to ensure required columns are specified, unique, and do not conflict. Also, column selectors now verify that essential outbox and topic dispatch columns are not inadvertently filtered out.
  • Optimized Checkpoint Handling: Modified Kafka and Pulsar sinks to collect and send checkpoint messages to all statically configured topics, the default topic, and dynamically discovered topics (from per-row dispatch), ensuring robust checkpointing across all active topics.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • api/v2/model.go
    • Added OutboxConfig to SinkConfig for API exposure.
    • Implemented conversion logic for OutboxConfig between internal and API models.
  • api/v2/model_test.go
    • Added a test case to verify the correct conversion of OutboxConfig.
  • downstreamadapter/sink/columnselector/column_selector.go
    • Modified ColumnSelectors to store outboxRequiredColumns.
    • Updated VerifyTables to prevent filtering out columns required by outbox configuration or topic dispatch rules.
  • downstreamadapter/sink/columnselector/column_selector_test.go
    • Added new tests to verify column selector behavior with outbox and topic dispatch column requirements.
  • downstreamadapter/sink/eventrouter/event_router.go
    • Modified EventRouter to support column-based topic dispatch, accepting RowEvent for GetTopicForRowChange.
    • Updated GetTopicForDDL to fall back to the default topic if column placeholders are used.
    • Adjusted GetActiveTopics to skip row-dependent topics during static topic discovery.
    • Added GetTopicDispatchColumns to retrieve columns referenced in topic rules and extractColumnValuesForTopic for runtime value extraction.
  • downstreamadapter/sink/eventrouter/event_router_test.go
    • Added tests for column-based topic dispatch, including scenarios with valid, null, and empty column values.
    • Included tests for DDL fallback with column placeholders and GetActiveTopics behavior.
  • downstreamadapter/sink/eventrouter/topic/expression.go
    • Refactored topic expression parsing to support column:<name> placeholders.
    • Updated validation logic for Kafka, Avro, and Pulsar to account for new placeholder types.
    • Introduced SubstituteWithValues, UsesColumnPlaceholders, and ReferencedColumns methods.
  • downstreamadapter/sink/eventrouter/topic/expression_pulsar_test.go
    • Added a test case for Pulsar topic validation and substitution with column placeholders.
  • downstreamadapter/sink/eventrouter/topic/expression_test.go
    • Added tests for column placeholder substitution, Avro validation, topic length constraints, and panic scenarios.
  • downstreamadapter/sink/eventrouter/topic/topic.go
    • Updated Generator interface to include methods for column placeholder awareness and referenced columns.
    • Modified DynamicTopicGenerator to pre-parse expression tokens and track column placeholder usage.
  • downstreamadapter/sink/eventrouter/topic/topic_test.go
    • Added tests to ensure DynamicTopicGenerator panics when Substitute is called with column placeholders without row context.
  • downstreamadapter/sink/helper/helper.go
    • Included ProtocolOutboxJSON in the GetFileExtension function.
  • downstreamadapter/sink/kafka/sink.go
    • Modified Kafka sink to handle per-row topic dispatch, track dynamically discovered topics, and update checkpoint topic generation logic.
  • downstreamadapter/sink/kafka/sink_test.go
    • Added a test for getCheckpointTopics to verify correct topic collection for checkpoints.
  • downstreamadapter/sink/pulsar/sink.go
    • Modified Pulsar sink to handle per-row topic dispatch, track dynamically discovered topics, and update checkpoint topic generation logic.
  • downstreamadapter/sink/pulsar/sink_test.go
    • Added a test for getCheckpointTopics to verify correct topic collection for checkpoints.
  • pkg/config/sink.go
    • Added OutboxConfig struct and integrated it into SinkConfig.
    • Implemented validation logic for OutboxConfig to check for required fields and uniqueness.
    • Updated ValidateProtocol to include specific validation for outbox-json protocol and its compatibility with Kafka schemes.
  • pkg/config/sink_protocol.go
    • Added ProtocolOutboxJSON to the Protocol enum.
    • Updated IsBatchEncode, ParseSinkProtocolFromString, and String methods to support the new protocol.
  • pkg/config/sink_protocol_test.go
    • Added test cases for ProtocolOutboxJSON parsing, string conversion, and batch encoding behavior.
  • pkg/config/sink_test.go
    • Added tests for ShouldSendBootstrapMsg with outbox-json protocol.
    • Introduced TestValidateAndAdjustOutboxProtocol to cover various validation scenarios for OutboxConfig.
  • pkg/sink/codec/builder.go
    • Integrated outbox.NewEncoder for the ProtocolOutboxJSON.
  • pkg/sink/codec/common/config.go
    • Added OutboxIDColumn, OutboxKeyColumn, OutboxValueColumn, and OutboxHeaderColumns fields to Config.
    • Updated Apply to populate outbox-related fields from SinkConfig.
    • Enhanced Validate to include checks for required outbox columns and header configurations.
  • pkg/sink/codec/common/message.go
    • Added Headers field to Message struct and introduced MessageHeader struct.
    • Updated Length calculation to account for message headers.
  • pkg/sink/codec/outbox/encoder.go
    • Added new file: Implemented EventEncoder for outbox-json protocol.
    • Encodes single insert rows into Kafka messages with configurable ID, key, value, and headers.
    • Skips non-insert rows, DDL events, and checkpoint events, as per outbox pattern requirements.
  • pkg/sink/codec/outbox/encoder_test.go
    • Added new file: Contains tests for outbox.Encoder, covering insert row encoding, skipping non-insert rows, required column validation, and DDL/checkpoint handling.
  • pkg/sink/kafka/mock_factory.go
    • Updated mock Sarama producers to include Headers in SendMessage and SendMessages.
  • pkg/sink/kafka/sarama_async_producer.go
    • Modified AsyncSend to pass Kafka message headers.
    • Added toSaramaHeaders utility function to convert internal message headers to Sarama format.
  • pkg/sink/kafka/sarama_headers_test.go
    • Added new file: Tests for the toSaramaHeaders utility function.
  • pkg/sink/kafka/sarama_sync_producer.go
    • Modified SendMessage and SendMessages to pass Kafka message headers.
  • tests/integration_tests/_utils/check_changefeed_checkpoint
    • Added new file: A utility script to poll a changefeed's checkpoint_ts and wait for it to reach a target TSO.
  • tests/integration_tests/kafka_outbox_json_basic/conf/changefeed.toml
    • Added new file: Configuration for the basic outbox-json integration test.
  • tests/integration_tests/kafka_outbox_json_basic/data/data.sql
    • Added new file: DML statements for the basic outbox-json integration test, including inserts, updates, and deletes.
  • tests/integration_tests/kafka_outbox_json_basic/data/ddl.sql
    • Added new file: DDL statements for the basic outbox-json integration test.
  • tests/integration_tests/kafka_outbox_json_basic/run.sh
    • Added new file: Integration test script for basic outbox-json protocol functionality, verifying inserts and silent skipping of updates/deletes.
  • tests/integration_tests/kafka_outbox_json_column_selector/conf/changefeed_ok.toml
    • Added new file: Configuration for the column selector 'OK' case in outbox-json integration tests.
  • tests/integration_tests/kafka_outbox_json_column_selector/conf/changefeed_reject.toml
    • Added new file: Configuration for the column selector 'REJECT' case in outbox-json integration tests.
  • tests/integration_tests/kafka_outbox_json_column_selector/data/ddl.sql
    • Added new file: DDL statements for the column selector outbox-json integration test.
  • tests/integration_tests/kafka_outbox_json_column_selector/run.sh
    • Added new file: Integration test script for column selector validation with outbox-json protocol, testing both valid and invalid configurations.
  • tests/integration_tests/kafka_outbox_json_headers/conf/changefeed.toml
    • Added new file: Configuration for the outbox-json headers integration test, mapping source columns to Kafka headers.
  • tests/integration_tests/kafka_outbox_json_headers/data/data.sql
    • Added new file: DML statements for the outbox-json headers integration test, including W3C TraceContext values.
  • tests/integration_tests/kafka_outbox_json_headers/data/ddl.sql
    • Added new file: DDL statements for the outbox-json headers integration test.
  • tests/integration_tests/kafka_outbox_json_headers/run.sh
    • Added new file: Integration test script for outbox-json protocol with custom Kafka headers, verifying header propagation.
  • tests/integration_tests/kafka_outbox_json_topic_dispatch/conf/changefeed.toml
    • Added new file: Configuration for the outbox-json topic dispatch integration test, using column placeholders in topic rules.
  • tests/integration_tests/kafka_outbox_json_topic_dispatch/data/data.sql
    • Added new file: DML statements for the outbox-json topic dispatch integration test, with different tenant IDs for dynamic topics.
  • tests/integration_tests/kafka_outbox_json_topic_dispatch/data/ddl.sql
    • Added new file: DDL statements for the outbox-json topic dispatch integration test.
  • tests/integration_tests/kafka_outbox_json_topic_dispatch/run.sh
    • Added new file: Integration test script for outbox-json protocol with per-row topic dispatch, verifying dynamic topic creation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 39ae5379-e1cf-42a2-9384-3fcf0b605225

📥 Commits

Reviewing files that changed from the base of the PR and between 7323b49 and 161f7d5.

📒 Files selected for processing (7)
  • downstreamadapter/sink/eventrouter/event_router.go
  • downstreamadapter/sink/eventrouter/event_router_test.go
  • downstreamadapter/sink/kafka/sink.go
  • downstreamadapter/sink/kafka/sink_test.go
  • downstreamadapter/sink/pulsar/sink.go
  • downstreamadapter/sink/pulsar/sink_test.go
  • pkg/config/sink.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • downstreamadapter/sink/kafka/sink_test.go
  • downstreamadapter/sink/kafka/sink.go

📝 Walkthrough

Walkthrough

Adds end-to-end support for an outbox JSON sink: new API/internal OutboxConfig and conversions, ProtocolOutboxJSON, outbox JSON encoder (INSERT-only, headers), tokenized topic expressions with column placeholders and row-based dispatch, selector/router validations, producer header propagation, discovered row topics with unified checkpointing, and integration tests.

Changes

Cohort / File(s) Summary
API types & conversions
api/v2/model.go, api/v2/model_test.go
Add public OutboxConfig, attach to SinkConfig, and propagate conversions between API and internal configs with deep-copied header maps; add unit test for conversion.
Sink config & protocol
pkg/config/sink.go, pkg/config/sink_test.go, pkg/config/sink_protocol.go, pkg/config/sink_protocol_test.go
Add Outbox field and OutboxConfig type, validation helpers, OutboxRequiredColumns(), and new protocol ProtocolOutboxJSON with tests and validation rules.
Codec plumbing & message shape
pkg/sink/codec/builder.go, pkg/sink/codec/common/config.go, pkg/sink/codec/common/message.go
Expose outbox fields in encoder Config, select outbox encoder in factory, add MessageHeader type and Message.Headers with length accounting.
Outbox JSON encoder
pkg/sink/codec/outbox/encoder.go, pkg/sink/codec/outbox/encoder_test.go
New encoder converting INSERT row events to messages, enforcing required columns (ID/Key/Value and headers), populating headers, skipping non-inserts, enforcing max message size, with unit tests.
Topic expression & generator
downstreamadapter/sink/eventrouter/topic/expression.go, .../expression_pulsar_test.go, .../expression_test.go, topic.go, topic_test.go
Replace regex validation with tokenized parser; add {column:<name>} placeholders and APIs SubstituteWithValues, UsesColumnPlaceholders, ReferencedColumns; update generators to support per-row substitution and related tests.
Event router & dispatch
downstreamadapter/sink/eventrouter/event_router.go, event_router_test.go
Make topic resolution row-based GetTopicForRowChange(row), add GetTopicDispatchColumns(), extract per-row values for placeholders, and extend VerifyTables for topic/outbox column checks with tests.
Column selector validation
downstreamadapter/sink/columnselector/column_selector.go, column_selector_test.go
Track outbox-required columns, include topic-dispatch columns in required set, reject selections that filter required outbox/topic columns; add tests for acceptance/rejection scenarios.
Sink runtime & checkpointing
downstreamadapter/sink/kafka/sink.go, .../kafka/sink_test.go, downstreamadapter/sink/pulsar/sink.go, .../pulsar/sink_test.go
Discover runtime row topics, compute per-row topic via RowEvent + GetTopicForRowChange, track discoveredRowTopics with mutex, and unify checkpoint broadcasting via getCheckpointTopics(); add tests.
Kafka header propagation
pkg/sink/kafka/sarama_async_producer.go, pkg/sink/kafka/sarama_sync_producer.go, pkg/sink/kafka/mock_factory.go, pkg/sink/kafka/sarama_headers_test.go
Convert MessageHeader to Sarama RecordHeader, attach headers to producer messages, and add unit test for header conversion.
Helpers
downstreamadapter/sink/helper/helper.go
Map ProtocolOutboxJSON to .json file extension for file outputs.
Integration tests & fixtures
tests/integration_tests/* (multiple dirs)
Add multiple integration test suites and fixtures for basic outbox behavior, headers, column-selector acceptance/rejection, topic-dispatch by column, and helper scripts to poll changefeed checkpoints.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant API as API Layer (api/v2)
    participant Config as Config Layer (pkg/config)
    participant Router as EventRouter
    participant Encoder as Outbox Encoder
    participant MQ as Message Queue

    App->>API: Create ReplicaConfig with `Sink.OutboxConfig`
    API->>Config: ToInternalReplicaConfig() (propagate OutboxConfig)
    Config->>Config: Validate OutboxConfig & protocol
    Config->>Router: Initialize router (topic expressions)

    Note over App,Router: DML processing
    App->>Router: Emit RowEvent (INSERT)
    Router->>Router: Extract column values for topic placeholders
    Router->>Encoder: Pass RowEvent with resolved topic
    Encoder->>Encoder: Extract ID/Key/Value and header columns
    Encoder->>MQ: Build Message with Headers and emit
    MQ->>MQ: Convert headers to broker format & publish
Loading
sequenceDiagram
    participant ColumnSel as ColumnSelector
    participant Router as EventRouter
    participant Config as SinkConfig

    ColumnSel->>Router: GetTopicDispatchColumns(schema, table)
    ColumnSel->>Config: OutboxRequiredColumns()
    ColumnSel->>ColumnSel: required := topicCols ∪ outboxCols
    ColumnSel->>ColumnSel: Verify retained columns include required
    alt missing required column
        ColumnSel-->>ColumnSel: Fail VerifyTables (ErrColumnSelectorFailed)
    else
        ColumnSel-->>ColumnSel: Accept selection
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels

lgtm, approved

Suggested reviewers

  • wk989898
  • lidezhu
  • hongyunyan

Poem

🐰 I nibble tokens, map each name,

Headers hop and find their frame,
Inserts sing while others rest,
Topics sprout from column-guest,
Outbox carrots delivered best.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding outbox-json protocol support with per-row topic dispatch for Kafka sinks, which aligns with the primary objective of supporting the transactional outbox pattern.
Description check ✅ Passed The description covers the problem statement (Issue #4325), explains what changed and how it works, includes test categories (unit and integration tests), addresses performance and compatibility concerns, mentions documentation needs, and provides a well-written release note.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@benmeadowcroft benmeadowcroft marked this pull request as ready for review March 3, 2026 18:40
Copy link

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

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 significant new functionality to support the transactional outbox pattern and per-row topic dispatch for Kafka sinks. The changes are extensive, including a major refactoring of topic expression parsing to support column-based placeholders, updates to the Kafka and Pulsar sinks to handle dynamic topics, and the addition of a new outbox-json protocol. The implementation is robust and well-supported by new unit and integration tests. My review includes one suggestion to refactor duplicated code to improve long-term maintainability.

Note: Security Review did not run due to the size of the PR.

@ti-chi-bot ti-chi-bot bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 3, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":502,"request":{"method":"PATCH","url":"https://api.github.com/repos/pingcap/ticdc/issues/comments/3992891420","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: failure by coderabbit.ai -->\n\n> [!CAUTION]\n> ## Review failed\n> \n> Failed to post review comments\n\n<!-- end of auto-generated comment: failure by coderabbit.ai -->\n\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis pull request implements support for an outbox JSON protocol across the CDC system. It introduces the OutboxConfig type, adds ProtocolOutboxJSON as a new sink protocol, creates an outbox JSON encoder that converts INSERT events into messages with header mappings, enables row-based topic dispatch using column placeholders, and validates column selection and topic dispatch compatibility with outbox configurations.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API and Configuration Types** <br> `api/v2/model.go`, `api/v2/model_test.go`, `pkg/config/sink.go`, `pkg/config/sink_test.go`|Introduce OutboxConfig public type with column mappings (IDColumn, KeyColumn, ValueColumn, HeaderColumns). Add conversion logic in ReplicaConfig methods to propagate OutboxConfig between API and internal representations. Validate outbox protocol compatibility with Kafka/SSL schemes.|\n|**Protocol Enum and Parsing** <br> `pkg/config/sink_protocol.go`, `pkg/config/sink_protocol_test.go`|Add ProtocolOutboxJSON constant and update ParseSinkProtocolFromString to recognize \"outbox-json\". Mark outbox-json as non-batch encoding via IsBatchEncode().|\n|**Topic Expression and Routing** <br> `downstreamadapter/sink/eventrouter/topic/expression.go`, `downstreamadapter/sink/eventrouter/topic/expression_test.go`, `downstreamadapter/sink/eventrouter/topic/expression_pulsar_test.go`, `downstreamadapter/sink/eventrouter/topic/topic.go`, `downstreamadapter/sink/eventrouter/topic/topic_test.go`|Rewrite topic expression parsing to token-based approach supporting column placeholders {column:<name>}. Add SubstituteWithValues, UsesColumnPlaceholders, and ReferencedColumns methods to Generator interface and implementations. Enable dynamic topic generation from row column values.|\n|**Event Router and Dispatch** <br> `downstreamadapter/sink/eventrouter/event_router.go`, `downstreamadapter/sink/eventrouter/event_router_test.go`|Change GetTopicForRowChange signature to accept RowEvent instead of schema/table strings. Implement row-based column value extraction for topic placeholder substitution. Add GetTopicDispatchColumns() to expose columns referenced by topic placeholders. Update table verification for topic-dispatch and outbox column visibility.|\n|**Column Selection Validation** <br> `downstreamadapter/sink/columnselector/column_selector.go`, `downstreamadapter/sink/columnselector/column_selector_test.go`|Add outboxRequiredColumns tracking and validation in VerifyTables. Reject column selections that filter out columns required by outbox config or topic dispatcher. Introduce tests validating rejection/acceptance of outbox and topic-dispatch columns.|\n|**Codec and Message Headers** <br> `pkg/sink/codec/common/config.go`, `pkg/sink/codec/common/message.go`, `pkg/sink/codec/builder.go`|Add Outbox config fields (OutboxIDColumn, KeyColumn, ValueColumn, HeaderColumns) to Config and validation logic. Introduce MessageHeader type and Headers field to Message. Update NewEventEncoder factory to instantiate outbox.NewEncoder for ProtocolOutboxJSON.|\n|**Outbox JSON Encoder** <br> `pkg/sink/codec/outbox/encoder.go`, `pkg/sink/codec/outbox/encoder_test.go`|Implement Encoder for outbox JSON protocol converting INSERT events to messages with Id and configurable header mappings. Enforce required column presence and non-null/non-empty values. Suppress checkpoint and DDL events. Include tests for insert encoding, row type filtering, and column validation.|\n|**Kafka Producer Headers Support** <br> `pkg/sink/kafka/sarama_async_producer.go`, `pkg/sink/kafka/sarama_sync_producer.go`, `pkg/sink/kafka/sarama_headers_test.go`, `pkg/sink/kafka/mock_factory.go`|Add toSaramaHeaders helper to convert MessageHeader to sarama.RecordHeader. Update AsyncSend and SendMessage paths to populate Headers field in ProducerMessage. Include unit test for header conversion.|\n|**Kafka and Pulsar Sinks** <br> `downstreamadapter/sink/kafka/sink.go`, `downstreamadapter/sink/kafka/sink_test.go`, `downstreamadapter/sink/pulsar/sink.go`, `downstreamadapter/sink/pulsar/sink_test.go`|Add discovered row topic tracking via discoveredRowTopicsMu and discoveredRowTopics map. Refactor topic selection to compute RowEvent for each row and invoke GetTopicForRowChange(). Consolidate checkpoint routing via new getCheckpointTopics() combining default, active, and discovered topics. Add helper methods for topic discovery management.|\n|**Helper Utilities** <br> `downstreamadapter/sink/helper/helper.go`|Update GetFileExtension to map ProtocolOutboxJSON to \".json\" file extension.|\n|**Integration Tests - Basic and Column Selection** <br> `tests/integration_tests/kafka_outbox_json_basic/*`, `tests/integration_tests/kafka_outbox_json_column_selector/*`|Add test scenarios validating basic outbox encoding (insert-only, skip updates/deletes) and column selector validation (accepting non-required column exclusions, rejecting required column exclusions). Include DDL setup, data fixtures, and shell scripts with Kafka message validation.|\n|**Integration Tests - Headers and Topic Dispatch** <br> `tests/integration_tests/kafka_outbox_json_headers/*`, `tests/integration_tests/kafka_outbox_json_topic_dispatch/*`|Add test scenarios for header-to-column mapping with OTEL tracing headers and per-tenant topic dispatch using row column values. Include DDL, multi-row data fixtures, and validation of dynamic topic creation and header propagation.|\n|**Test Utilities** <br> `tests/integration_tests/_utils/check_changefeed_checkpoint`|Add bash utility script to poll changefeed checkpoint progress against target timestamp, supporting integration test synchronization.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant App as Application\n    participant API as API Layer<br/>(api/v2)\n    participant Config as Config Layer<br/>(pkg/config)\n    participant Router as Event Router<br/>(eventrouter)\n    participant Encoder as Outbox Encoder<br/>(codec/outbox)\n    participant Kafka as Kafka Producer\n    \n    App->>API: Create ReplicaConfig with<br/>Sink.OutboxConfig\n    API->>Config: ToInternalReplicaConfig()<br/>converts OutboxConfig\n    Config->>Config: Validate OutboxConfig<br/>(columns, headers)\n    Config->>Router: Initialize with<br/>Sink.Outbox config\n    Router->>Router: Parse topic expression<br/>for column placeholders\n    \n    App->>Router: Insert RowEvent\n    Router->>Router: Extract column values<br/>for topic placeholders\n    Router-->>App: Resolved topic\n    \n    App->>Encoder: AppendRowChangedEvent<br/>(INSERT only)\n    Encoder->>Encoder: Extract required columns<br/>(ID, Key, Value)\n    Encoder->>Encoder: Map header columns<br/>to row values\n    Encoder->>Encoder: Build Message with<br/>Headers\n    \n    Encoder-->>Kafka: Build() returns<br/>Messages\n    Kafka->>Kafka: Convert headers to<br/>Sarama format\n    Kafka-->>App: Publish to topic with<br/>headers\n```\n\n```mermaid\nsequenceDiagram\n    participant ValidatePath as Validation Path\n    participant ColumnSel as Column Selector<br/>(columnselector)\n    participant Router as Event Router\n    participant Config as Config<br/>(sink.go)\n    \n    ValidatePath->>ColumnSel: VerifyTables(schema, table)\n    ColumnSel->>Router: GetTopicDispatchColumns()<br/>Get topic placeholder columns\n    ColumnSel->>Config: Outbox columns<br/>(ID, Key, Value, Headers)\n    ColumnSel->>ColumnSel: Compute required columns:<br/>topicColumns + outboxColumns\n    \n    ColumnSel->>ColumnSel: For each selected column,<br/>check against required set\n    \n    alt Column filtered but required\n        ColumnSel-->>ValidatePath: Reject with<br/>ErrColumnSelectorFailed\n    else All required columns present\n        ColumnSel-->>ValidatePath: Accept configuration\n    end\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~60 minutes\n\n## Possibly related issues\n\n- pingcap/ticdc#4325: This PR implements the transactional outbox feature by introducing OutboxConfig, the outbox-json protocol, an insert-only encoder with header mappings, and row-based topic dispatch using column placeholders.\n\n## Suggested labels\n\n`lgtm`, `approved`\n\n## Suggested reviewers\n\n- wk989898\n- hongyunyan\n- lidezhu\n\n## Poem\n\n> 🐰 With outbox protocol now in place,\n> Headers hop to topics with grace,\n> Columns dance in token streams bright,\n> Insert-only events, routing quite right! 📨✨\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 1 | ❌ 2</summary>\n\n### ❌ Failed checks (1 warning, 1 inconclusive)\n\n|     Check name     | Status         | Explanation                                                                                                                                                                                                                                                                                | Resolution                                                                                                                                               |\n| :----------------: | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning     | Docstring coverage is 11.94% which is insufficient. The required threshold is 80.00%.                                                                                                                                                                                                      | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                       |\n|     Title check    | ❓ Inconclusive | The title 'Outbox support POC' describes a real aspect of the changeset (outbox protocol support), but is vague and only partially covers the main changes. It lacks specificity about the scope and doesn't highlight the key features like topic dispatch or the JSON encoding protocol. | Consider a more specific title like 'Add outbox-json protocol with per-row topic dispatch for Kafka sinks' to clearly convey the main changes and scope. |\n\n<details>\n<summary>✅ Passed checks (1 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                                                                                                             |\n| :---------------: | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Description check | ✅ Passed | The PR description comprehensively addresses the template requirements, including issue reference, clear explanation of changes and how they work, test coverage (unit and integration), answers to key questions about performance and compatibility, and an appropriate release note. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=pingcap/ticdc&utm_content=4340)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/pingcap/ticdc/issues/comments/3992891420","status":502,"headers":{"cache-control":"no-cache","connection":"close","content-security-policy":"default-src 'none'; style-src 'unsafe-inline'; img-src data:;","content-type":"text/html; charset=utf-8","strict-transport-security":"max-age=31536000; includeSubDomains; preload","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-request-id":"3040:93941:E55ACC:3D5936C:69A72DC0","x-xss-protection":"0"},"data":"<!DOCTYPE html>\r\n<!--\r\n\r\nHello future GitHubber! I bet you're here to remove those nasty inline styles,\r\nDRY up these templates and make 'em nice and re-usable, right?\r\n\r\nPlease, don't. https://github.com/styleguide/templates/2.0\r\n\r\n-->\r\n<html>\r\n  <head>\r\n    <title>Unicorn! &middot; GitHub</title>\r\n    <style type=\"text/css\" media=\"screen\">\r\n      body {\r\n        background-color: #f1f1f1;\r\n        margin: 0;\r\n        font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\r\n      }\r\n\r\n      .container { margin: 50px auto 40px auto; width: 600px; text-align: center; }\r\n\r\n      a { color: #4183c4; text-decoration: none; }\r\n      a:hover { text-decoration: underline; }\r\n\r\n      h1 { letter-spacing: -1px; line-height: 60px; font-size: 60px; font-weight: 100; margin: 0px; text-shadow: 0 1px 0 #fff; }\r\n      p { color: rgba(0, 0, 0, 0.5); margin: 10px 0 10px; font-size: 18px; font-weight: 200; line-height: 1.6em;}\r\n\r\n      ul { list-style: none; margin: 25px 0; padding: 0; }\r\n      li { display: table-cell; font-weight: bold; width: 1%; }\r\n\r\n      .logo { display: inline-block; margin-top: 35px; }\r\n      .logo-img-2x { display: none; }\r\n      @media\r\n      only screen and (-webkit-min-device-pixel-ratio: 2),\r\n      only screen and (   min--moz-device-pixel-ratio: 2),\r\n      only screen and (     -o-min-device-pixel-ratio: 2/1),\r\n      only screen and (        min-device-pixel-ratio: 2),\r\n      only screen and (                min-resolution: 192dpi),\r\n      only screen and (                min-resolution: 2dppx) {\r\n        .logo-img-1x { display: none; }\r\n        .logo-img-2x { display: inline-block; }\r\n      }\r\n\r\n      #suggestions {\r\n        margin-top: 35px;\r\n        color: #ccc;\r\n      }\r\n      #suggestions a {\r\n        color: #666666;\r\n        font-weight: 200;\r\n        font-size: 14px;\r\n        margin: 0 10px;\r\n      }\r\n\r\n    </style>\r\n  </head>\r\n  <body>\r\n\r\n    <div class=\"container\">\r\n      <p>\r\n        <img width=\"200\" src=\"data:image/png;base64,\r\n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\">\r\n      </p>\r\n\r\n      <p><strong>We had issues producing the response to your request.</strong></p>\r\n      <p>Sorry about that. Please try refreshing and contact us if the problem persists.</p>\r\n      <div id=\"suggestions\">\r\n        <a href=\"https://github.com/contact\">Contact Support</a> &mdash;\r\n        <a href=\"https://www.githubstatus.com\">GitHub Status</a> &mdash;\r\n        <a href=\"https://twitter.com/githubstatus\">@githubstatus</a>\r\n      </div>\r\n\r\n      <a href=\"/\" class=\"logo logo-img-1x\">\r\n        <img width=\"32\" height=\"32\" title=\"\" alt=\"\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMTZCRDY3REIzRjAxMUUyQUQzREIxQzRENUFFNUM5NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMTZCRDY3RUIzRjAxMUUyQUQzREIxQzRENUFFNUM5NiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkUxNkJENjdCQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkUxNkJENjdDQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+SM9MCAAAA+5JREFUeNrEV11Ik1EY3s4+ddOp29Q5b0opCgKFsoKoi5Kg6CIhuwi6zLJLoYLopq4qsKKgi4i6CYIoU/q5iDAKs6syoS76IRWtyJ+p7cdt7sf1PGOD+e0c3dygAx/67ZzzPM95/877GYdHRg3ZjMXFxepQKNS6sLCwJxqNNuFpiMfjVs4ZjUa/pmmjeD6VlJS8NpvNT4QQ7mxwjSsJiEQim/1+/9lgMHgIr5ohuxG1WCw9Vqv1clFR0dCqBODElV6v90ogEDjGdYbVjXhpaendioqK07CIR7ZAqE49PT09BPL2PMgTByQGsYiZlQD4uMXtdr+JxWINhgINYhGT2MsKgMrm2dnZXgRXhaHAg5jEJodUAHxux4LudHJE9RdEdA+i3Juz7bGHe4mhE9FNrgwBCLirMFV9Okh5eflFh8PR5nK5nDabrR2BNJlKO0T35+Li4n4+/J+/JQCxhmu5h3uJoXNHPbmWZAHMshWB8l5/ipqammaAf0zPDDx1ONV3vurdidqwAQL+pEc8sLcAe1CCvQ3YHxIW8Pl85xSWNC1hADDIv0rIE/o4J0k3kww4xSlwIhcq3EFFOm7KN/hUGOQkt0CFa5WpNJlMvxBEz/IVQAxg/ZRZl9wiHA63yDYieM7DnLP5CiAGsC7I5sgtYKJGWe2A8seFqgFJrJjEPY1Cn3pJ8/9W1e5VWsFDTEmFrBcoDhZJEQkXuhICMyKpjhahqN21hRYATKfUOlDmkygrR4o4C0VOLGJKrOITKB4jijzdXygBKixyC5TDQdnk/Pz8qRw6oOWGlsTKGOQW6OH6FBWsyePxdOXLTgxiyebILZCjz+GLgMIKnXNzc49YMlcRdHXcSwxFVgTInQhC9G33UhNoJLuqq6t345p9y3eUy8OTk5PjAHuI9uo4b07FBaOhsu0A4Unc+T1TU1Nj3KsSSE5yJ65jqF2DDd8QqWYmAZrIM2VlZTdnZmb6AbpdV9V6ec9znf5Q7HjYumdRE0JOp3MjitO4SFa+cZz8Umqe3TCbSLvdfkR/kWDdNQl5InuTcysOcpFT35ZrbBxx4p3JAHlZVVW1D/634VRt+FvLBgK/v5LV9WS+10xMTEwtRw7XvqOL+e2Q8V3AYIOIAXQ26/heWVnZCVfcyKHg2CBgTpmPmjYM8l24GyaUHyaIh7XwfR9ErE8qHoDfn2LTNAVC0HX6MFcBIP8Bi+6F6cdW/DICkANRfx99fEYFQ7Nph5i/uQiA214gno7K+guhaiKg9gC62+M8eR7XsBsYJ4ilam60Fb7r7uAj8wFyuwM1oIOWgfmDy6RXEEQzJMPe23DXrVS7rtyD3Df8z/FPgAEAzWU5Ku59ZAUAAAAASUVORK5CYII=\" />\r\n      </a>\r\n\r\n      <a href=\"/\" class=\"logo logo-img-2x\">\r\n        <img width=\"32\" height=\"32\" title=\"\" alt=\"\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpEQUM1QkUxRUI0MUMxMUUyQUQzREIxQzRENUFFNUM5NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpEQUM1QkUxRkI0MUMxMUUyQUQzREIxQzRENUFFNUM5NiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkUxNkJENjdGQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkUxNkJENjgwQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+hfPRaQAAB6lJREFUeNrsW2mM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\" />\r\n      </a>\r\n    </div>\r\n  </body>\r\n</html>\r\n"}}

@benmeadowcroft benmeadowcroft changed the title Outbox support POC Add outbox-json protocol with per-row topic dispatch for Kafka sinks POC Mar 3, 2026
…ional comments

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
… address review comments

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
downstreamadapter/sink/kafka/sink.go (1)

260-267: Add a static-topic fast path in calculateKeyPartitions.

GetTopicForRowChange + GetPartitionNum now run per row even when the matched rule has no {column:...} placeholders and the topic is table-static. That adds avoidable hot-path overhead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@downstreamadapter/sink/kafka/sink.go` around lines 260 - 267, The hot-path
calls to s.comp.eventRouter.GetTopicForRowChange and
s.comp.topicManager.GetPartitionNum should be avoided inside
calculateKeyPartitions for rules that are table-static and have no {column:...}
placeholders; detect that condition (use the matched rule metadata or pattern
that indicates "table-static" and absence of column placeholders) and compute
topic and partitionNum once outside the per-row loop (e.g., when the rule is
matched or when calculateKeyPartitions is invoked) and reuse those values for
all rows, falling back to the existing per-row
GetTopicForRowChange/GetPartitionNum logic only when placeholders exist; update
calculateKeyPartitions, and where it is called, to accept or read the
precomputed topic/partitionNum so the per-row path no longer calls
GetTopicForRowChange/GetPartitionNum.
downstreamadapter/sink/pulsar/sink.go (1)

354-361: Add a static-topic fast path in calculateKeyPartitions.

For non-placeholder topic rules, topic/partition lookup is invariant per table. Doing this per row adds avoidable hot-path overhead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@downstreamadapter/sink/pulsar/sink.go` around lines 354 - 361, The
calculateKeyPartitions hot path currently calls
s.comp.eventRouter.GetTopicForRowChange and s.comp.topicManager.GetPartitionNum
per row; add a static-topic fast path by detecting non-placeholder topic rules
(i.e., rules that do not depend on row data) and caching the resolved topic ->
partition count per table (use a map keyed by table ID/name stored on the sink
or s.comp with a sync.RWMutex or sync.Map for thread-safety). On first encounter
of a table with a non-placeholder rule, call GetTopicForRowChange and
GetPartitionNum once, store the result, and then in calculateKeyPartitions
return the cached partitionNum without per-row lookups; still fall back to the
existing per-row logic for placeholder/row-dependent rules and invalidate/update
the cache if routing rules can change at runtime.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@downstreamadapter/sink/kafka/sink.go`:
- Around line 557-599: discoveredRowTopics is only ever appended to (via
addDiscoveredRowTopic) causing unbounded growth and expensive checkpoint fanout;
change the representation from map[string]struct{} to map[string]time.Time (or
similar last-seen token) and add eviction: update addDiscoveredRowTopic to
record a timestamp when a topic is seen, implement a
pruneStaleDiscoveredRowTopics (or prune inside snapshotDiscoveredRowTopics) that
removes entries older than a configured retention window or when the map exceeds
a max capacity, and call that pruning under the same discoveredRowTopicsMu so
snapshotDiscoveredRowTopics returns a bounded set; ensure functions referenced
are addDiscoveredRowTopic, snapshotDiscoveredRowTopics and any new prune helper
and keep mutex usage consistent.

In `@downstreamadapter/sink/pulsar/sink.go`:
- Around line 535-579: The discoveredRowTopics map (used by
addDiscoveredRowTopic, snapshotDiscoveredRowTopics and read by
getCheckpointTopics) is unbounded and will grow without eviction; change the
implementation to cap growth by storing metadata (e.g., lastSeen timestamp or
insertion order) instead of a plain map and evict stale/least-recent topics on
add or during snapshot; for example maintain a map[string]time.Time or a small
LRU structure and in addDiscoveredRowTopic update lastSeen and, if the size
exceeds a configured max (or topics older than a configured TTL), remove entries
before returning so snapshotDiscoveredRowTopics only returns currently valid
topics and getCheckpointTopics stays bounded.

In `@pkg/config/sink.go`:
- Around line 1106-1114: The validate() logic in pkg/config/sink.go currently
trims only for emptiness checks but does not persist normalized values, causing
fields like IDColumn/KeyColumn/ValueColumn to retain surrounding whitespace;
update validate() to call strings.TrimSpace and assign the trimmed results back
to o.IDColumn, o.KeyColumn and o.ValueColumn before performing the empty checks
(and do the same for the duplicate block around the 1117-1124 section), so
stored config uses trimmed column names during offset resolution/encoding.

In `@pkg/sink/codec/outbox/encoder.go`:
- Around line 136-137: Clean() is currently a no-op but must clear the encoder's
buffered state: update Encoder.Clean to reset e.messages (e.g. set e.messages =
nil or e.messages = e.messages[:0] to release/clear buffered entries) and also
reset any related counters or length fields on the Encoder instance if present
so no stale messages remain (refer to the Encoder type and its e.messages field
and any associated buffer length fields).
- Around line 70-72: The guard that checks if !event.IsInsert() currently
returns early without invoking the post-flush callback, which can break txn
post-flush callback chaining; modify the branch in the function containing the
event.IsInsert() check so that it calls the provided callback (the txn
post-flush callback passed into this encoder method, e.g.,
cb/onFlush/postFlushCallback) before returning, passing the same nil error (or
appropriate context) as other success paths, then return; keep the rest of the
method semantics unchanged.

---

Nitpick comments:
In `@downstreamadapter/sink/kafka/sink.go`:
- Around line 260-267: The hot-path calls to
s.comp.eventRouter.GetTopicForRowChange and s.comp.topicManager.GetPartitionNum
should be avoided inside calculateKeyPartitions for rules that are table-static
and have no {column:...} placeholders; detect that condition (use the matched
rule metadata or pattern that indicates "table-static" and absence of column
placeholders) and compute topic and partitionNum once outside the per-row loop
(e.g., when the rule is matched or when calculateKeyPartitions is invoked) and
reuse those values for all rows, falling back to the existing per-row
GetTopicForRowChange/GetPartitionNum logic only when placeholders exist; update
calculateKeyPartitions, and where it is called, to accept or read the
precomputed topic/partitionNum so the per-row path no longer calls
GetTopicForRowChange/GetPartitionNum.

In `@downstreamadapter/sink/pulsar/sink.go`:
- Around line 354-361: The calculateKeyPartitions hot path currently calls
s.comp.eventRouter.GetTopicForRowChange and s.comp.topicManager.GetPartitionNum
per row; add a static-topic fast path by detecting non-placeholder topic rules
(i.e., rules that do not depend on row data) and caching the resolved topic ->
partition count per table (use a map keyed by table ID/name stored on the sink
or s.comp with a sync.RWMutex or sync.Map for thread-safety). On first encounter
of a table with a non-placeholder rule, call GetTopicForRowChange and
GetPartitionNum once, store the result, and then in calculateKeyPartitions
return the cached partitionNum without per-row lookups; still fall back to the
existing per-row logic for placeholder/row-dependent rules and invalidate/update
the cache if routing rules can change at runtime.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e36a3ce and 620ae29.

📒 Files selected for processing (10)
  • downstreamadapter/sink/columnselector/column_selector.go
  • downstreamadapter/sink/eventrouter/event_router.go
  • downstreamadapter/sink/eventrouter/topic/expression.go
  • downstreamadapter/sink/eventrouter/topic/topic.go
  • downstreamadapter/sink/kafka/sink.go
  • downstreamadapter/sink/pulsar/sink.go
  • pkg/config/sink.go
  • pkg/config/sink_test.go
  • pkg/sink/codec/outbox/encoder.go
  • pkg/sink/kafka/sarama_async_producer.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/config/sink_test.go

benmeadowcroft and others added 2 commits March 4, 2026 11:00
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ic rules

For table-static topic rules (no column placeholders), GetTopicForRowChange and GetPartitionNum were called on every row of a DMLEvent even though they produce the same result for the whole event.

Add EventRouter.GetTopicForTable, which resolves the topic from schema and table alone when no column placeholders are present. In calculateKeyPartitions for both the Kafka and Pulsar sinks, call GetTopicForTable once per event before the row loop and defer GetPartitionNum to the first row that will actually be emitted, falling back to the existing per-row path only for column-placeholder rules. Skip-only events (e.g. outbox-json update/delete transactions) therefore never trigger a partition lookup.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
discoveredRowTopics only ever grew: every unique dynamic topic appended an entry that was never removed. For column-placeholder routing rules this causes unbounded memory growth and an ever-expanding set of checkpoint messages sent on every 5-second tick.

Fix by replacing map[string]struct{} with map[string]time.Time (last-seen timestamp). snapshotDiscoveredRowTopics now prunes entries older than discoveredTopicRetention (30 min) inline under the existing mutex, requiring no new goroutine. Topics that become active again are immediately re-added by addDiscoveredRowTopic, so eviction is self-healing.

Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
Signed-off-by: Ben Meadowcroft <ben.meadowcroft@pingcap.com>
@benmeadowcroft
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@benmeadowcroft
Copy link
Author

Can I get some guidance on the Docstring coverage check?

I believe all the public functions I added are documented, I can add additional comments to other functions if necessary, but I haven't done that as I didn't want to introduce unnecessary churn on items that weren't touched by this PR. If adding additional comments is wanted I can certainly do that, but wanted to check first on what the expectations were.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution This PR is from a community contributor. do-not-merge/needs-triage-completed first-time-contributor Indicates that the PR was contributed by an external member and is a first-time contributor. needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant