feat(jetstream): add API leader forwarding and stream purge options (C7+C8)

C7: JetStreamApiRouter now checks leadership before mutating operations.
Non-leader nodes return error code 10003 with a leader_hint field.
JetStreamMetaGroup gains IsLeader() and Leader for cluster-aware routing.

C8: StreamApiHandlers.HandlePurge accepts PurgeRequest options (filter,
seq, keep). StreamManager.PurgeEx implements subject-filtered purge,
sequence-based purge, keep-last-N, and filter+keep combinations.
This commit is contained in:
Joseph Doherty
2026-02-24 15:22:22 -05:00
parent d259a2d03e
commit 7116988d03
8 changed files with 627 additions and 5 deletions

View File

@@ -15,6 +15,7 @@ public sealed class JetStreamApiResponse
public JetStreamSnapshot? Snapshot { get; init; }
public JetStreamPullBatch? PullBatch { get; init; }
public bool Success { get; init; }
public ulong Purged { get; init; }
public static JetStreamApiResponse NotFound(string subject) => new()
{
@@ -40,6 +41,31 @@ public sealed class JetStreamApiResponse
Description = description,
},
};
/// <summary>
/// Returns a not-leader error with code 10003 and a leader_hint.
/// Go reference: jetstream_api.go:200-300 — non-leader nodes return this error
/// for mutating operations so clients can redirect.
/// </summary>
public static JetStreamApiResponse NotLeader(string leaderHint) => new()
{
Error = new JetStreamApiError
{
Code = 10003,
Description = "not leader",
LeaderHint = leaderHint,
},
};
/// <summary>
/// Returns a purge success response with the number of messages purged.
/// Go reference: jetstream_api.go:1200-1350 — purge response includes purged count.
/// </summary>
public static JetStreamApiResponse PurgeResponse(ulong purged) => new()
{
Success = true,
Purged = purged,
};
}
public sealed class JetStreamStreamInfo