feat: add quorum check before proposing entries (Gap 8.6)
Add HasQuorum() to RaftNode that counts peers with LastContact within 2 × ElectionTimeoutMaxMs and returns true only when self + current peers reaches majority. ProposeAsync now throws InvalidOperationException with "no quorum" when HasQuorum() returns false, preventing a partitioned leader from diverging the log. Add 14 tests in RaftQuorumCheckTests.cs covering single-node, 3-node, 5-node, boundary window, and heartbeat restore scenarios. Update RaftHealthTests.LastContact_updates_on_successful_replication to avoid triggering the new quorum guard.
This commit is contained in:
@@ -19,6 +19,20 @@ public sealed class RaftLog
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends an entry with an explicit timestamp. Used in tests and by the
|
||||
/// <see cref="CompactionPolicy.ByAge"/> policy to set controlled creation times.
|
||||
/// </summary>
|
||||
public RaftLogEntry AppendWithTimestamp(int term, string command, DateTime timestamp)
|
||||
{
|
||||
var entry = new RaftLogEntry(_baseIndex + _entries.Count + 1, term, command)
|
||||
{
|
||||
Timestamp = timestamp,
|
||||
};
|
||||
_entries.Add(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void AppendReplicated(RaftLogEntry entry)
|
||||
{
|
||||
if (_entries.Any(e => e.Index == entry.Index))
|
||||
@@ -79,4 +93,15 @@ public sealed class RaftLog
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record RaftLogEntry(long Index, int Term, string Command);
|
||||
/// <summary>
|
||||
/// A single RAFT log entry. Timestamp records when the entry was created (UTC) and
|
||||
/// is used by the <see cref="CompactionPolicy.ByAge"/> compaction policy.
|
||||
/// </summary>
|
||||
public sealed record RaftLogEntry(long Index, int Term, string Command)
|
||||
{
|
||||
/// <summary>
|
||||
/// UTC creation time. Defaults to <see cref="DateTime.UtcNow"/> at append time.
|
||||
/// Stored as a JSON-serializable property so it survives persistence round-trips.
|
||||
/// </summary>
|
||||
public DateTime Timestamp { get; init; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user