Scheduler: in-repo election, failover, and catch-up test coverage#1875
Merged
Conversation
Covers the orchestration paths that previously had only pure-helper unit tests here (electRole, becomeLeader, heartbeat, failoverCheck, runCatchUp, executeJob) using the same-process simulated-peer pattern: the engine's entire view of other nodes flows through server.nodes and rows in hdb_scheduler_state, so the test supplies both against the real engine module and a real store. Staleness is data-driven, so nothing waits out production thresholds; heartbeat/failover ticks are driven through small ForTests seams (same pattern as setCoolingFunctionForTests). Scenarios: sticky election deferral, no-promotion while the leader beats, stale-leader promotion with catch-up firing the missed occurrence (catchUp: true), lease renewal, step-down when a heartbeat finds a fresh competing lease (racing write), cold-start election, new-job baseline without immediate fire, and registration replacement (previously an assertion-free test). True-network multi-node coverage remains in the harper-pro cluster harness (replication is not part of this repo). Refs #1866, #1828, #951. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, comment accuracy The new 'loses a cold-start election to an alphabetically-preferred roster peer' case is the one outcome that only passes if nodeRoster()/pickNextLeader wiring is correct (review: the roster stub was previously inert with respect to every assertion). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces in-repo test coverage for the scheduler engine's election, heartbeat, and failover orchestration, adding test-only hooks to resources/scheduler/engine.ts and a comprehensive test suite in unitTests/resources/scheduler/engineElection.test.js. The feedback highlights two important improvements: first, addressing a potential race condition where an in-flight election promise could resolve after the engine is stopped, leaking timers; and second, replacing a flaky real-time delay in the heartbeat test with a deterministic backdated timestamp.
… stop; condition-wait for heartbeat assertion stopSchedulerEngine now bumps an engine epoch that electRole, becomeLeader, and failoverCheck capture before their awaits and re-check after — an in-flight election or promotion can no longer resurrect timers or claim the lease after a stop (with a regression test). The heartbeat-renewal assertion uses the shared waitFor condition-wait instead of a fixed 5ms sleep (coarse-clock flake). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jcohen-hdb
marked this pull request as ready for review
July 20, 2026 18:30
…oots harper dev <fixture> runs symlinkHarperModule against the component dir, planting node_modules/harper inside integrationTests/fixtures/* — untracked and unignored, it has previously slipped into a commit (#1828 required an amend). Discovered during runtime verification of this branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1866.
Summary
Adds unit coverage for the scheduler engine's election/heartbeat/failover/catch-up orchestration (
electRole,becomeLeader,heartbeat,failoverCheck,runCatchUp,executeJob) — previously backed in this repo only by pure-helper tests, with true-network validation living in the harper-pro cluster harness.Approach — same-process simulated peer (the
deploy-tracking-peer-branch.test.tspattern): true multi-node replication isn't available in this repo (replication ships as a separate component), but the engine's entire knowledge of other nodes flows through exactly two observables —server.nodes(normally populated by the replication component) and rows inhdb_scheduler_state(normally replicated). The test supplies both, against the real engine module and a real store, no sinon. Staleness is data-driven (a lease heartbeat stamped past the threshold is a dead leader), so nothing waits out production intervals; heartbeat/failover ticks are driven through three new@internalpass-through seams (electionSettledForTests,runHeartbeatForTests,runFailoverCheckForTests— same pattern assetCoolingFunctionForTests).Scenarios (a single node walked through its lifecycle): sticky-election deferral to a fresh peer lease → no premature promotion → stale-lease promotion with catch-up firing the missed occurrence (
catchUp: trueasserted) → lease renewal → step-down when a heartbeat finds a fresh competing lease → cold-start election win → roster-driven cold-start election loss (the one outcome that only passes ifnodeRoster()/pickNextLeaderwiring is correct, not just the pure function) → new-job baseline without immediate fire → registration replacement (upgrading a previously assertion-free test).Where to focus review
stopSchedulerEngine).A Harper-domain review pass ran pre-PR; its findings (inert roster stub, state-row cleanup, one overclaiming comment) are addressed in the second commit. Note:
npm run buildon currentmainreports pre-existing type errors inagent/bestPractices.tsandresources/DatabaseTransaction.ts— unrelated to this diff, which adds no TS errors.Refs #1828, #951.
Generated by an LLM (Claude Fable 5) pairing with @jcohen-hdb.
🤖 Generated with Claude Code