Skip to content

fix(replication): decode the server's resync response shape - #414

Open
reatang wants to merge 2 commits into
mainfrom
fix/replication-resync-wire-shape
Open

reatang wants to merge 2 commits into
mainfrom
fix/replication-resync-wire-shape

Conversation

@reatang

@reatang reatang commented Nov 8, 2026

Copy link
Copy Markdown
Member

Related issue

Related to rustfs/rustfs#8768 (the rc side of the report).

Background

Since rustfs/rustfs#5799 the server encodes the replication resync start/status response with the madmin-go ResyncTargetsInfo json tags: target, arn, resetid, startTime, endTime, resyncStatus, replicationCount, completedReplicationSize, failedReplicationCount, failedReplicationSize, bucket, object, Error, ResetBeforeDate.

rc still decoded the older PascalCase keys (Targets, Arn, ResetID, ...). serde matches keys case-sensitively and the target list is #[serde(default)], so a current server response decoded as an empty target list:

  • rc replicate resync start failed with expected one target, got 0 even though the server had started the resync.
  • rc replicate resync status always reported no targets, so a running or stuck resync was invisible.

Solution

  • Name each field of ReplicationResyncResponseDto / ReplicationResyncTargetDto explicitly with the key the server sends today.
  • Keep the previous PascalCase spellings as serde aliases so servers released before the change still decode.
  • Keep default on the target list, because madmin omits an empty list.

No CLI, JSON output, or config contract changes; only the wire decoding of the server response.

Tests

  • Rewrote the six resync fixtures to the body the current server actually sends. Before the fix, five tests failed with exactly the reported symptoms (zero targets on start, empty status).
  • Added replication_resync_status_decodes_current_and_legacy_wire_shapes, which decodes both shapes, checks every converted field, checks that both decode to the same result, and checks that {} decodes to an empty list.
  • cargo fmt --all --check, cargo clippy --workspace -- -D warnings, and cargo test --workspace (1989 passed, 0 failed) pass locally.
  • Not exercised against a live RustFS server; the fixtures match the shape locked by the server's own serialization tests.

RustFS servers serialize bucket resync start and status responses with
the madmin-go `ResyncTargetsInfo` json tags (`target`, `arn`, `resetid`,
`resyncStatus`, `replicationCount`, ...). The client expected PascalCase
keys (`Targets`, `Arn`, `ResetID`, ...). serde matches keys
case-sensitively and the target list defaulted to empty, so against a
current server `resync start` reported "expected one target, got 0"
after the server had accepted the run, and `resync status` always
returned an empty target list.

Decode the madmin-go keys and keep the PascalCase spellings as aliases
for servers released before the wire change. Test fixtures now use the
shape the server actually emits, with a separate test for the legacy
shape.
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.

1 participant