Skip to content

aws_dynamodb_cdc: support DynamoDB Global Tables for the checkpoint t… - #4529

Merged
squiidz merged 5 commits into
mainfrom
aws_dynamodb_cdc_global_table
Jun 26, 2026
Merged

aws_dynamodb_cdc: support DynamoDB Global Tables for the checkpoint t…#4529
squiidz merged 5 commits into
mainfrom
aws_dynamodb_cdc_global_table

Conversation

@squiidz

@squiidz squiidz commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

aws_dynamodb_cdc: support DynamoDB Global Tables for the checkpoint table

Add `global_table` / `global_table_replicas` options so the auto-created
checkpoint table is provisioned as a DynamoDB Global Table (v2), replicating
shard checkpoints across regions for low-RPO multi-region failover.

Checkpoints are keyed by a region-portable identifier (the source table name)
and store the stream ARN and record timestamp. Resume is layered: same-region
restarts resume exactly via AfterSequenceNumber (unchanged behavior), while a
failed-over region resumes from the trim horizon, skipping records at or before
the low-water-mark timestamp of the prior region's checkpoints. Table creation
enables DynamoDB Streams and provisions/reconciles replica regions; all new
behavior is gated behind `global_table` and is a no-op when disabled.

@claude

claude Bot commented Jun 17, 2026

Copy link
Copy Markdown

Commits
LGTM

Review
Reviewed the addition of DynamoDB Global Table support for the aws_dynamodb_cdc checkpoint table (portable table-name key in global mode, replica reconciliation, time-based failover resume, and the new dynamodb_approximate_creation_time metadata / dynamodb_cdc_failover_skipped metric).

The change is well-structured and follows project patterns: the CheckpointerConfig struct replaces positional args, errors are wrapped with %w in gerund form, context is propagated correctly, field names use constants, the resume cache is synchronized via sync.Once, license headers match the package (RCL/enterprise), and the failover skip logic (\!After(cutoff)) matches the documented at-least-once design with proper nil guards. The parallel lastTimestamps map is bounded alongside lastCheckpoints, and both single- and multi-table read paths are wired consistently. New unit tests cover checkpointer create/reconcile/resume, batcher timestamp tracking, and config parsing/validation.

LGTM

@squiidz
squiidz force-pushed the aws_dynamodb_cdc_global_table branch from b957474 to 1ac155d Compare June 22, 2026 15:05
Comment thread internal/impl/aws/dynamodb/input_cdc.go
squiidz added 2 commits June 25, 2026 18:38
…able

Add `global_table` / `global_table_replicas` options so the auto-created
checkpoint table is provisioned as a DynamoDB Global Table (v2), replicating
shard checkpoints across regions for low-RPO multi-region failover.

Checkpoints are keyed by a region-portable identifier (the source table name)
and store the stream ARN and record timestamp. Resume is layered: same-region
restarts resume exactly via AfterSequenceNumber (unchanged behavior), while a
failed-over region resumes from the trim horizon, skipping records at or before
the low-water-mark timestamp of the prior region's checkpoints. Table creation
enables DynamoDB Streams and provisions/reconciles replica regions; all new
behavior is gated behind `global_table` and is a no-op when disabled.
Addresses review feedback: the global_table field descriptions claimed
the option only affects table creation and is a no-op on an existing
table, but ensureTableExists reconciles replicas (issuing UpdateTable) on
the existing-table path in global mode. Worse, a pre-existing non-global
checkpoint table uses a StreamArn hash key that is incompatible with the
global-mode TableId key schema, so reusing it would reconcile replicas
onto the wrong table and write checkpoints under an undefined key.

- Add validateGlobalTableSchema: when the checkpoint table already exists
  and global_table is enabled, require its hash key to be TableId and
  fail fast with an actionable error otherwise, before any UpdateTable.
- Introduce key-attribute name constants so the create path, the key
  schema check, and checkpointKey can't drift apart.
- Align the global_table / global_table_replicas descriptions with the
  reconcile-on-existing behavior and the global-mode schema requirement.
@squiidz
squiidz force-pushed the aws_dynamodb_cdc_global_table branch from fb98f70 to 543dc7c Compare June 25, 2026 22:49
@redpanda-data redpanda-data deleted a comment from claude Bot Jun 25, 2026
@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Commits
LGTM

Review
Reviewed the aws_dynamodb_cdc Global Table checkpoint feature against the §5 CDC Standard and project Go/test patterns. The change is well-structured and thoroughly unit-tested (programmable fake DynamoDB client, contiguous-frontier timestamp ordering, replica reconciliation, schema-mismatch fail-fast, and all resume modes). Verified: the deterministic cdctest gate only checks config field names and the new global_table/global_table_replicas fields are additive with no new divergence; the new dynamodb_approximate_creation_time metadata follows the connector’s established dynamodb_-prefixed convention; the time-based failover cutoff (min low-water-mark, skip <= cutoff) is at-least-once safe; nil checks guard all ApproximateCreationDateTime dereferences; mutex usage and RCL license headers are correct; and config validation/linting is present.

LGTM

Comment thread internal/impl/aws/dynamodb/input_cdc.go Outdated
isCDCCheckpointStale used Checkpointer.Get() and probed the returned
sequence number with GetShardIterator against the current region's
stream. In global mode after a regional failover, the checkpoint row
(keyed by TableId) holds another region's sequence number, which is
invalid against this region's stream, so the probe errored and the
checkpoint was misclassified as stale — clearing the snapshot marker and
forcing a full re-snapshot on the first restart after failover. That
breaks the exact scenario the global-table feature exists for, with no
user workaround.

Use the global-table-aware ResolveResume() instead and only probe for
staleness on an exact, same-region resume; failover and default resumes
read from the trim horizon and are never stale.
@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Commits
LGTM

Review
Reviewed the aws_dynamodb_cdc Global Tables checkpoint feature: portable TableId keying, schema fail-fast guard, replica reconciliation, layered resume resolution (exact / time-based failover / default), frontier-timestamp tracking in the batcher, and the failover stale-checkpoint regression fix. New global-mode behavior is correctly gated and is a no-op when global_table is disabled. License headers, config validation, and metadata naming are consistent with the existing connector and the flat CDC fleet shape. Unit coverage via DynamoDB fakes is solid (schema validation, replica add, resume classification, failover skip).

LGTM

Comment thread internal/impl/aws/dynamodb/input_cdc.go Outdated
for _, record := range records {
// Global-table failover: skip records already processed in the prior region.
if !failoverCutoff.IsZero() && record.Dynamodb != nil && record.Dynamodb.ApproximateCreationDateTime != nil {
if !record.Dynamodb.ApproximateCreationDateTime.After(failoverCutoff) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Failover skip can drop unprocessed records, violating at-least-once (§5.4.2).

The cutoff is the minimum ApproximateCreationTime across the prior region's foreign checkpoint rows (prepareResume in checkpoint.go: if !cutoffSet || ts.Before(c.cutoff)). Here records are skipped when !After(cutoff), i.e. record.time <= cutoff.

DynamoDB Streams ApproximateCreationDateTime is second-granularity by default, so multiple records commonly share one timestamp. On the shard whose checkpoint is the minimum (the cutoff), records in that same second that occur after the checkpointed position were never processed in the prior region, yet <= cutoff skips them on resume — those records are silently dropped. That breaks the at-least-once guarantee the feature documents ("at-least-once, replaying from the trim horizon up to the last replicated record time").

Skipping strictly-before the cutoff (record.time.Before(cutoff)) is the at-least-once-safe choice: it reprocesses the boundary second (acceptable duplicates) rather than dropping it. The same issue exists in convertRecordsToBatch at line 2813.

See CONTRIBUTING §5.4.2 (At-least-once delivery). The boundary case is also untested — TestConvertTableRecordsToBatch_FailoverSkipsOldRecords only exercises minute-apart records.

@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Commits

  1. Commit c6dc018 — message Update internal/impl/aws/dynamodb/input_cdc.go with an empty body. This is the GitHub web-edit default and violates the commit message policy: it should be scoped (aws_dynamodb_cdc: <imperative summary>), and it is vague/uninformative about what actually changed. Please rename/squash it into a descriptive message.

The remaining three commits follow the aws_dynamodb_cdc: ... convention and are well-scoped.

Review

The Global Tables checkpoint feature is well-structured (portable TableId key, schema guard on reuse, global-table-aware ResolveResume, and the stale-checkpoint fix for the failover case). One correctness concern on the failover skip path:

  1. At-least-once violation in failover record skipping (input_cdc.go#L2204-L2208, duplicated at L2811-L2815). The cutoff is the minimum foreign-checkpoint timestamp, and records are skipped when \!After(cutoff) (<= cutoff). With second-granularity ApproximateCreationDateTime, records in the cutoff second that occur after the checkpointed position on the min-watermark shard were never processed in the prior region but are skipped on resume — dropping them and breaking the documented at-least-once guarantee (CONTRIBUTING §5.4.2). Skipping strictly-before (Before(cutoff)) is the safe choice. See inline comment.

The global-table failover replay skipped records with
ApproximateCreationDateTime <= cutoff, where cutoff is the minimum
ApproximateCreationTime across the prior region's checkpoints. Because
that timestamp is only second-granular, records sharing the cutoff
second on the min-watermark shard may have followed the checkpointed
position and never been processed in the prior region — skipping them
dropped data and broke the documented at-least-once guarantee
(CONTRIBUTING §5.4.2).

Skip only records strictly before the cutoff, replaying the boundary
second (acceptable duplicates under at-least-once) instead of dropping
it. Extract the decision into a single shouldSkipFailoverRecord helper
used by both convert paths (previously duplicated) and cover the
boundary second with unit tests.
@claude

claude Bot commented Jun 26, 2026

Copy link
Copy Markdown

Commits

  1. Commit c6dc018Update internal/impl/aws/dynamodb/input_cdc.go: the message is a vague, auto-generated GitHub-suggestion headline with an empty body. It names a file path rather than describing the change, so it does not match any accepted format (system: message, chore:, or a sentence-case repo-wide message) and fails the message-quality bar. Please reword to e.g. aws_dynamodb_cdc: <what changed> and squash it into the relevant logical commit.

The other four commits are well-scoped and correctly formatted.

Review

This is an incremental feature on the existing aws_dynamodb_cdc connector: a multi-region (DynamoDB Global Table) checkpoint mode plus a dynamodb_approximate_creation_time metadata field driving time-based failover resume. It preserves the flat fleet message shape, keeps the durable checkpoint table, checkpoints on snapshot completion, and adds thorough unit tests with a faked DynamoDB client. The at-least-once boundary-second concern (CONTRIBUTING §5.4.2) was explicitly handled in the final commit, and validation/linting for the new config fields is in place.

LGTM — no code-level issues found that warrant blocking.

@squiidz
squiidz merged commit d33d3ab into main Jun 26, 2026
9 checks passed
@squiidz
squiidz deleted the aws_dynamodb_cdc_global_table branch June 26, 2026 15:03
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.

2 participants