Skip to content

fix #253: snapshot stale-file corruption on retry + configurable chunk timeout - #368

Merged
JoshuaChi merged 13 commits into
mainfrom
fix/253-verify-doc-snapshot-behavior
May 8, 2026
Merged

JoshuaChi merged 13 commits into
mainfrom
fix/253-verify-doc-snapshot-behavior

Conversation

@JoshuaChi

@JoshuaChi JoshuaChi commented May 6, 2026 •

Copy link
Copy Markdown
Contributor

What Does This PR Do?

Fixes two production bugs in snapshot transfer: (1) a stale partial temp file from an interrupted transfer is now truncated instead of appended to on retry, preventing silent snapshot corruption; (2) the per-chunk receive timeout is now configurable via SnapshotConfig instead of hardcoded to 10 seconds. Adds fault-path integration tests and a new snapshot-guarantees.md operator guide.

Type:

  • Bug Fix (with test)
  • Feature (issue #___ approved)
  • Documentation
  • Test/Coverage
  • Performance (with benchmark)

Why Is This Needed?

Bug 1 — stale temp file corruption (production impact)

When a snapshot transfer fails mid-way (timeout, leader crash, network drop), temp-snapshot.part.tar.gz remains on disk. On the next retry, the old code used append(true) — new chunks were appended after the stale data, producing a corrupted tar.gz. The leader retries indefinitely; the follower can never apply the snapshot and gets permanently stuck.

Fix: SnapshotAssembler::new() now opens the temp file with truncate(true), clearing stale data before every new transfer.

Bug 2 — hardcoded chunk timeout

receive_chunk_timeout_in_sec was hardcoded to 10 seconds in process_snapshot_stream(). Large snapshots over slow networks always timed out. Fix: moved to SnapshotConfig with a default of 30 seconds.


Checklist

Required:

  • make test passes
  • Added tests for new code
  • Commits squashed to 1-2 logical units

If changing APIs:

  • Updated relevant docs (snapshot-guarantees.md + overview.md)
  • Explained why complexity is justified

Testing

How tested:

  • Unit tests: test_assembler_on_stale_temp_file_does_not_append_old_data — red before fix, green after; confirms append(true) → truncate(true) change
  • Integration tests:
    • test_snapshot_receiver_truncates_stale_temp_file — pre-injects stale file, verifies learner catches up and snapshot-only entries (purged from log) are readable
    • test_snapshot_transfer_resumes_after_leader_change — kills leader mid-transfer, verifies learner recovers from new leader

For bug fixes:

  • Added test that fails without this fix

Does This Follow d-engine's Principles?

  • Solves a real problem for most users (not just my edge case)
  • Keeps implementation simple
  • Doesn't bloat the API surface

Reviewer Notes

Bug 1: The key diff is one line in snapshot_assembler.rs — .append(true) → .write(true).truncate(true). The rest is tests and docs.

Bug 2: SnapshotConfig gains one new field receive_chunk_timeout_in_sec (default 30). Existing configs without this field get the default via #[serde(default)] — no breaking change.

Estimated review complexity:

  • Quick (< 100 lines)
  • Medium (< 300 lines)
  • Deep (> 300 lines)

Summary by CodeRabbit

  • New Features

    • Per-chunk snapshot receive timeout is now configurable (defaults to 30s) and zero is rejected.
  • Bug Fixes

    • Temp snapshot files are created/truncated to avoid appending stale data.
    • Snapshot delivery honors the configured per-chunk timeout instead of a hard-coded value.
  • Tests

    • New integration tests for interrupted transfers, leader-change during transfer, stale-temp-file handling, and related watch/membership scenarios.
  • Documentation

    • Added "Snapshot Guarantees" guide and clarified readiness/watch behavior.

@coderabbitai

coderabbitai Bot commented May 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

This PR was authored by the user configured for CodeRabbit reviews. CodeRabbit does not review PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 92f170a9-051a-4a1a-93b9-896d92146fd3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a per-chunk snapshot receive timeout (default 30s) to SnapshotConfig and validates it, uses that timeout during snapshot streaming, changes temp snapshot file open to truncate (avoid append), adds unit and integration tests validating stale-temp behavior and leader-change recovery, and adds "Snapshot Guarantees" docs.

Changes

Snapshot Timeout Configurability & Stale File Handling

Layer / File(s) Summary
Data Shape
d-engine-core/src/config/raft.rs
SnapshotConfig gains pub receive_chunk_timeout_in_sec: u64 with serde default default_receive_chunk_timeout_in_sec() (30) and validation requiring > 0.
Core Implementation
d-engine-core/src/state_machine_handler/default_state_machine_handler.rs, d-engine-core/src/state_machine_handler/snapshot_assembler.rs
Replaced hard-coded 10s chunk timeout with config.receive_chunk_timeout_in_sec; OpenOptions for temp snapshot file changed from append(true) to write(true).truncate(true) (with create).
Integration & Wiring
d-engine-core/src/test_utils/common.rs
Test snapshot config updated to include receive_chunk_timeout_in_sec: 30.
Unit Tests
d-engine-core/src/state_machine_handler/snapshot_assembler_test.rs
Adds test_assembler_on_stale_temp_file_does_not_append_old_data, confirming stale temp files are overwritten and not prepended.
Integration Tests
d-engine-server/tests/snapshot_and_recovery/*, d-engine-server/tests/snapshot_and_recovery/mod.rs
Adds two embedded integration tests: interrupted-transfer truncation and leader-change-during-transfer recovery; registers new test modules.
Documentation
d-engine/src/docs/server_guide/snapshot-guarantees.md, d-engine/src/docs/server_guide/mod.rs, d-engine/src/docs/overview.md
Adds "Snapshot Guarantees" guide, exposes it as snapshot_guarantees module, and links it in docs index.
Cleanup / Minor Docs & Tests
d-engine-server/tests/snapshot_and_recovery/snapshot_concurrent_replication_embedded.rs, d-engine-server/tests/snapshot_and_recovery/snapshot_follower_generation_embedded.rs, d-engine-core/src/event.rs, d-engine-server/src/api/embedded.rs, d-engine-server/src/membership/membership_snapshot.rs, d-engine-server/tests/watch_and_subscriptions/watch_membership_embedded.rs
Removed license headers from two test files; doc comment clarifications; added test helper wait_for_node_in_snapshot and replaced immediate assertions with timeout-backed waits in membership test.

Sequence Diagram

sequenceDiagram
    participant Leader
    participant Learner
    participant SnapshotAssembler
    participant Filesystem
    Leader->>Learner: initiate snapshot transfer (chunks)
    Learner->>SnapshotAssembler: stream incoming chunks (per-chunk timeout)
    SnapshotAssembler->>Filesystem: open temp file (create, write, truncate)
    SnapshotAssembler->>Filesystem: write chunk N
    Note right of SnapshotAssembler: if chunk not received within timeout,\nstream errors/abort
    SnapshotAssembler->>Filesystem: flush, close, atomic rename to final snapshot
    Learner->>Leader: confirm catch-up / apply snapshot
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • deventlab/d-engine#354: Modifies SnapshotConfig in d-engine-core/src/config/raft.rs and touches related snapshot defaults/config.

Poem

🐰 I nibble stale crumbs from a partial file,
Trim them clean and hop on for a mile.
Chunks wait thirty seconds, then stream in neat,
Temp files truncated — snapshots complete.
Leaders fall, learners rise; recovery is sweet.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main changes: fixing stale-file corruption on snapshot retry and adding configurable chunk timeout, both of which are core to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 `@d-engine-core/src/config/raft.rs`:
- Around line 513-518: SnapshotConfig::validate() must reject zero-valued
timeouts because Duration::from_secs(0) causes tokio::time::timeout to fire
immediately and silently break snapshot transfers; update
SnapshotConfig::validate() to check receive_chunk_timeout_in_sec (and the other
timeout fields referenced in the same config block) and return an Err or
validation failure if any are 0 (require >= 1 second or a sensible non-zero
minimum), referencing the receive_chunk_timeout_in_sec field name and
SnapshotConfig::validate to locate where to add the guard.

In `@d-engine-server/tests/snapshot_and_recovery/mod.rs`:
- Around line 16-17: The Test Coverage section in mod.rs is out of date: add
bullets for the newly registered modules snapshot_interrupted_transfer_embedded
and snapshot_leader_change_during_transfer_embedded to the "## Test Coverage"
list so the overview matches the actual registered suites; update the coverage
bullets to include those two module names alongside the existing entries and
ensure formatting matches the surrounding list style.

In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs`:
- Around line 239-245: Run rustfmt on the test file to fix the formatting issue
flagged by CI: reformat the assert_eq! block and the following info! invocation
in snapshot_and_recovery::snapshot_interrupted_transfer_embedded.rs so the
multiline assert_eq!(actual, format!("value_{i}").into_bytes(), "...") and the
info!("Snapshot-only entries [0, {}, {}] verified on Learner",
snapshot_only_boundary / 2, snapshot_only_boundary - 1) call conform to cargo
fmt style; simply run `cargo fmt` (or `cargo fmt --all`) and commit the
resulting changes.

In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs`:
- Around line 197-203: Replace the fixed
tokio::time::sleep(Duration::from_millis(400)).await with a polling loop that
observes the learner's snapshot-transfer progress and only kills the leader when
a mid-transfer condition is detected: repeatedly check the learner's working
directory for the presence of the temporary snapshot file (e.g.
"temp-snapshot.part.tar.gz") while also verifying that the replicated key
(referenced as last_key in the test) is still absent, and once that observable
condition is true call engines.remove(leader_idx) to drop the leader; target the
checks around the learner node object used in this test so you wait for an
actual in-progress snapshot instead of sleeping a fixed duration.
- Around line 247-264: The test currently verifies entries from
new_leader_engine/new_leader_client, but per the review we must verify recovered
data from the learner to catch partial/corrupt snapshot cases; replace the final
verification loop that iterates 0..BASELINE_ENTRIES to read from learner_engine
(or learner_client = learner_engine.client().clone()) instead of
new_leader_engine/new_leader_client and run the same get_linearizable and
assert_eq checks against format!("value_{i}") so the end-of-test integrity
asserts the learner (not the replacement leader) has all expected keys below the
purge boundary.

In `@d-engine/src/docs/server_guide/snapshot-guarantees.md`:
- Line 52: Update the documentation defaults to match the actual constants:
change the config reference table entries for max_log_entries_before_snapshot,
chunk_size, and max_bandwidth_mbps to reflect the code defaults
(default_max_log_entries_before_snapshot = 1000, default_chunk_size = 1024 bytes
(1 KB), default_max_bandwidth_mbps = 1), and revise the inline wording that
currently says "chunks larger than the default 1 MB" to "chunks larger than the
default 1 KB"; apply the same corrections to the repeated section around lines
68-76 so all mentions match the real defaults in d-engine-core's raft.rs.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6228f2ea-20cf-415d-b519-3d6be7db5655

📥 Commits

Reviewing files that changed from the base of the PR and between 1bd2a0e and d57183e.

📒 Files selected for processing (13)
  • d-engine-core/src/config/raft.rs
  • d-engine-core/src/state_machine_handler/default_state_machine_handler.rs
  • d-engine-core/src/state_machine_handler/snapshot_assembler.rs
  • d-engine-core/src/state_machine_handler/snapshot_assembler_test.rs
  • d-engine-core/src/test_utils/common.rs
  • d-engine-server/tests/snapshot_and_recovery/mod.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_concurrent_replication_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_follower_generation_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs
  • d-engine/src/docs/overview.md
  • d-engine/src/docs/server_guide/mod.rs
  • d-engine/src/docs/server_guide/snapshot-guarantees.md
💤 Files with no reviewable changes (2)
  • d-engine-server/tests/snapshot_and_recovery/snapshot_follower_generation_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_concurrent_replication_embedded.rs

Comment thread d-engine-core/src/config/raft.rs
Comment thread d-engine-server/tests/snapshot_and_recovery/mod.rs
Comment thread d-engine/src/docs/server_guide/snapshot-guarantees.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@d-engine-server/src/api/embedded.rs`:
- Around line 492-493: Update the doc bullet for Self::wait_ready to correctly
describe that it waits for leader election / no-op commit readiness (i.e.,
cluster consensus readiness), not for the local RPC server; explicitly
distinguish it from Self::watch_membership (membership changes) and
Self::leader_change_notifier (leader election notifications) so readers are
directed to the correct signal.

In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs`:
- Line 251: The test currently returns Ok(()) while four EmbeddedEngine
instances are still running; before returning, explicitly shut down all
EmbeddedEngine instances created in this test by calling their
shutdown/stop/close method (and await it if async) or otherwise join their
background task(s) so they don't leak — e.g., invoke the shutdown/join method on
each EmbeddedEngine variable used in snapshot_interrupted_transfer_embedded.rs
and await completion before the final Ok(()).

In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs`:
- Around line 195-203: The test currently removes the leader wrapper with
engines.remove(leader_idx) after calling learner_engine.wait_ready(), but that
doesn't guarantee the actual leader process stopped; update the test to
explicitly stop and await shutdown of the old leader so we exercise a real crash
during snapshot transfer: locate the leader wrapper referenced by leader_idx /
old_leader_id (the EmbeddedEngine instance) and call its proper
shutdown/stop/await method (e.g., EmbeddedEngine::shutdown(), stop(), or await
termination) instead of merely removing it, ensuring the leader's runtime is
killed and awaited before proceeding with the rest of the test.
- Line 272: The test returns without stopping the remaining EmbeddedEngine
instances (e.g., the learner and surviving voter nodes), leaving tasks running;
before the final Ok(()) call, call and await each node's stop() (or explicitly
invoke EmbeddedEngine::stop()) for all embedded node variables created in the
test (learner, surviving_voters, any other engines) so they are cleanly shut
down and don't outlive the test; ensure you handle any errors from stop()
(propagate or log) and only then return Ok(()) so EmbeddedEngine::drop won't log
skipped stops or leave background tasks running.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a63e552-9961-469f-8080-22db0705ea22

📥 Commits

Reviewing files that changed from the base of the PR and between d57183e and b1fd3e9.

📒 Files selected for processing (9)
  • d-engine-core/src/config/raft.rs
  • d-engine-core/src/event.rs
  • d-engine-server/src/api/embedded.rs
  • d-engine-server/src/membership/membership_snapshot.rs
  • d-engine-server/tests/snapshot_and_recovery/mod.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs
  • d-engine-server/tests/watch_and_subscriptions/watch_membership_embedded.rs
  • d-engine/src/docs/server_guide/snapshot-guarantees.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • d-engine/src/docs/server_guide/snapshot-guarantees.md

Comment thread d-engine-server/src/api/embedded.rs Outdated
@codecov

codecov Bot commented May 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.42424% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...c/state_machine_handler/snapshot_assembler_test.rs 89.74% 4 Missing ⚠️
d-engine-core/src/config/raft_test.rs 85.71% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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
`@d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs`:
- Around line 76-78: The learner's initial_cluster entry for node n3 has an
incorrect role value (role = 3) that conflicts with the primary cluster (where
n3 is role = 1); update the learner config's initial_cluster node entry for name
'n3' (the map with id = 3) to set role = 1 so it matches the primary cluster and
the NODE_ROLE_FOLLOWER enum.

In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs`:
- Around line 150-155: The learner's initial_cluster entry incorrectly marks
node 3 as role = 3 (LEADER) causing a topology mismatch; update the learner's
initial_cluster array (the block named initial_cluster in
snapshot_leader_change_during_transfer_embedded.rs) so that the entry for id = 3
uses role = 1 (FOLLOWER) to match the original cluster configuration (ensure id
= 1,2,3 all have role = 1).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76eb922e-2706-4d0f-8d3c-36bfe39bb14b

📥 Commits

Reviewing files that changed from the base of the PR and between b1fd3e9 and 42eaf8d.

📒 Files selected for processing (4)
  • d-engine-core/src/config/raft_test.rs
  • d-engine-server/src/api/embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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
`@d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs`:
- Around line 251-254: The loop calling engine.stop() can return early on the
first Err and leak remaining engines; change the shutdown to attempt stopping
all engines (e.g., iterate and call engine.stop().await for each, collecting any
Errs) and only then return an error if any stops failed; apply the same pattern
for learner_engine.stop().await so all stops are attempted; reference the
engines collection and learner_engine and the stop() calls when making the
change.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 77ab5ac3-b013-4c4c-86e4-766215d388d7

📥 Commits

Reviewing files that changed from the base of the PR and between 42eaf8d and eb391bf.

📒 Files selected for processing (2)
  • d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs (1)

208-225: 💤 Low value

Redundant engine.node_id() != old_leader_id guard — old_leader was already removed.

engines.remove(leader_idx) at line 205 drops the old leader from the slice, so the inner loop at line 212 can no longer encounter it. The != old_leader_id predicate is always true in this loop. Not a correctness bug, just dead logic.

🤖 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
`@d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs`
around lines 208 - 225, The loop checking for a new leader contains a redundant
guard comparing engine.node_id() != old_leader_id because
engines.remove(leader_idx) already removed the old leader; remove the dead
predicate from the inner if so the condition is simply engine.is_leader() (leave
new_leader_id assignment, break logic and timeout sleep intact), referencing
engines.remove(leader_idx), old_leader_id, new_leader_id, engine.is_leader(),
and engine.node_id() to locate and update the code.
d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs (1)

82-88: ⚡ Quick win

Consider adding [raft.election] to the cluster config for consistent CI stability.

The companion test (snapshot_leader_change_during_transfer_embedded.rs) pins election_timeout_min = 300 / election_timeout_max = 3000 to bound re-election latency. This test writes 150 entries before proceeding; a transient leader step-down with a large default election timeout could push total runtime past the 15-second wait_for_snapshot budget on slow CI runners.

🔧 Suggested addition
 [raft]
 general_raft_timeout_duration_in_ms = 5000
+
+[raft.election]
+election_timeout_min = 300
+election_timeout_max = 3000
+
 [raft.snapshot]
🤖 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
`@d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs`
around lines 82 - 88, Add an explicit [raft.election] section to the cluster
config used in snapshot_interrupted_transfer_embedded.rs to bound re-election
latency: set election_timeout_min and election_timeout_max (e.g., 300 and 3000)
so leader re-elections are predictable under CI; update the config string that
currently contains [raft] and [raft.snapshot] (the same config used by
wait_for_snapshot and the test that writes 150 entries) to include the new
[raft.election] block with those timeout values.
🤖 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.

Nitpick comments:
In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs`:
- Around line 82-88: Add an explicit [raft.election] section to the cluster
config used in snapshot_interrupted_transfer_embedded.rs to bound re-election
latency: set election_timeout_min and election_timeout_max (e.g., 300 and 3000)
so leader re-elections are predictable under CI; update the config string that
currently contains [raft] and [raft.snapshot] (the same config used by
wait_for_snapshot and the test that writes 150 entries) to include the new
[raft.election] block with those timeout values.

In
`@d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs`:
- Around line 208-225: The loop checking for a new leader contains a redundant
guard comparing engine.node_id() != old_leader_id because
engines.remove(leader_idx) already removed the old leader; remove the dead
predicate from the inner if so the condition is simply engine.is_leader() (leave
new_leader_id assignment, break logic and timeout sleep intact), referencing
engines.remove(leader_idx), old_leader_id, new_leader_id, engine.is_leader(),
and engine.node_id() to locate and update the code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 291533c2-65bf-4663-a959-6ea3daf9dc3b

📥 Commits

Reviewing files that changed from the base of the PR and between eb391bf and 24bda67.

📒 Files selected for processing (4)
  • d-engine-server/src/api/embedded_test.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_interrupted_transfer_embedded.rs
  • d-engine-server/tests/snapshot_and_recovery/snapshot_leader_change_during_transfer_embedded.rs
  • d-engine-server/tests/watch_and_subscriptions/watch_membership_embedded.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • d-engine-server/tests/watch_and_subscriptions/watch_membership_embedded.rs

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