docs: refresh differences for remaining jetstream parity

This commit is contained in:
Joseph Doherty
2026-02-23 10:22:39 -05:00
parent 4adc9367e6
commit ee6809aedc

View File

@@ -417,33 +417,36 @@ The following items from the original gap list have been implemented:
## 11. JetStream
> The Go JetStream surface is ~37,500 lines across jetstream.go, stream.go, consumer.go, filestore.go, memstore.go, raft.go. The .NET implementation has ~700 lines covering a minimal subset. Verified by `JetStreamApiRouter.cs` registration.
> The Go JetStream surface is ~37,500 lines across jetstream.go, stream.go, consumer.go, filestore.go, memstore.go, raft.go. The .NET implementation has expanded API and runtime parity coverage but remains partial versus full Go semantics.
### JetStream API ($JS.API.* subjects)
| Subject | Go | .NET | Notes |
|---------|:--:|:----:|-------|
| `STREAM.CREATE.<name>` | Y | Y | Only API handler implemented |
| `STREAM.CREATE.<name>` | Y | Y | |
| `STREAM.INFO.<name>` | Y | Y | |
| `STREAM.UPDATE.<name>` | Y | N | |
| `STREAM.DELETE.<name>` | Y | N | |
| `STREAM.NAMES` | Y | N | |
| `STREAM.LIST` | Y | N | |
| `STREAM.PURGE.<name>` | Y | N | Storage has `PurgeAsync()` but no API handler |
| `STREAM.MSG.GET.<name>` | Y | N | |
| `STREAM.MSG.DELETE.<name>` | Y | N | |
| `DIRECT.GET.<name>` | Y | N | KV-style direct access |
| `STREAM.UPDATE.<name>` | Y | Y | |
| `STREAM.DELETE.<name>` | Y | Y | |
| `STREAM.NAMES` | Y | Y | |
| `STREAM.LIST` | Y | Y | |
| `STREAM.PURGE.<name>` | Y | Y | |
| `STREAM.MSG.GET.<name>` | Y | Y | |
| `STREAM.MSG.DELETE.<name>` | Y | Y | |
| `DIRECT.GET.<name>` | Y | Y | Includes direct payload response shape |
| `CONSUMER.CREATE.<stream>` | Y | Y | |
| `CONSUMER.INFO.<stream>.<durable>` | Y | Y | |
| `CONSUMER.DELETE.<stream>.<durable>` | Y | N | |
| `CONSUMER.NAMES.<stream>` | Y | N | |
| `CONSUMER.LIST.<stream>` | Y | N | |
| `CONSUMER.PAUSE.<stream>.<durable>` | Y | N | |
| `STREAM.LEADER.STEPDOWN.<name>` | Y | N | |
| `META.LEADER.STEPDOWN` | Y | N | |
| `STREAM.SNAPSHOT.<name>` | Y | N | |
| `STREAM.RESTORE.<name>` | Y | N | |
| `INFO` (account info) | Y | N | |
| `CONSUMER.DELETE.<stream>.<durable>` | Y | Y | |
| `CONSUMER.NAMES.<stream>` | Y | Y | |
| `CONSUMER.LIST.<stream>` | Y | Y | |
| `CONSUMER.PAUSE.<stream>.<durable>` | Y | Y | |
| `CONSUMER.RESET.<stream>.<durable>` | Y | Y | |
| `CONSUMER.UNPIN.<stream>.<durable>` | Y | Y | |
| `CONSUMER.MSG.NEXT.<stream>.<durable>` | Y | Y | |
| `STREAM.LEADER.STEPDOWN.<name>` | Y | Y | |
| `META.LEADER.STEPDOWN` | Y | Y | |
| `STREAM.SNAPSHOT.<name>` | Y | Y | Snapshot/restore shape implemented; in-memory semantics |
| `STREAM.RESTORE.<name>` | Y | Y | Snapshot/restore shape implemented; in-memory semantics |
| `INFO` (account info) | Y | Y | |
### Stream Configuration
@@ -452,8 +455,8 @@ The following items from the original gap list have been implemented:
| Subjects | Y | Y | |
| Replicas | Y | Y | Wires RAFT replica count |
| MaxMsgs limit | Y | Y | Enforced via `EnforceLimits()` |
| Retention (Limits/Interest/WorkQueue) | Y | N | Only MaxMsgs trimming; Interest and WorkQueue not implemented |
| Discard policy (Old/New) | Y | N | |
| Retention (Limits/Interest/WorkQueue) | Y | Partial | Policy enums + validation branch exist; full runtime semantics incomplete |
| Discard policy (Old/New) | Y | Partial | Model support exists; runtime discard behavior not fully enforced |
| MaxBytes / MaxAge (TTL) | Y | N | |
| MaxMsgsPer (per-subject limit) | Y | N | |
| MaxMsgSize | Y | N | |
@@ -474,16 +477,16 @@ The following items from the original gap list have been implemented:
| Ephemeral consumers | Y | N | Only durable |
| AckPolicy.None | Y | Y | |
| AckPolicy.Explicit | Y | Y | `AckProcessor` tracks pending with expiry |
| AckPolicy.All | Y | N | |
| AckPolicy.All | Y | Partial | In-memory ack floor behavior implemented; full wire-level ack contract remains limited |
| Redelivery on ack timeout | Y | Partial | `NextExpired()` detects expired; limit not enforced |
| DeliverPolicy (All/Last/New/StartSeq/StartTime) | Y | N | Always delivers from beginning |
| DeliverPolicy (All/Last/New/StartSeq/StartTime) | Y | Partial | Policy enums added; fetch behavior still mostly starts at beginning |
| FilterSubject (single) | Y | Y | |
| FilterSubjects (multiple) | Y | N | |
| MaxAckPending | Y | N | |
| Idle heartbeat | Y | N | Field in model; not implemented |
| Idle heartbeat | Y | Partial | Push engine emits heartbeat frames for configured consumers |
| Flow control | Y | N | |
| Rate limiting | Y | N | |
| Replay policy | Y | N | |
| Replay policy | Y | Partial | Policy enum exists; replay timing semantics not fully implemented |
| BackOff (exponential) | Y | N | |
### Storage Backends
@@ -515,7 +518,7 @@ MemStore has basic append/load/purge with `Dictionary<long, StoredMessage>` unde
| Feature | Go (5 037 lines) | .NET (212 lines) | Notes |
|---------|:--:|:----:|-------|
| Leader election / term tracking | Y | Partial | In-process; nodes hold direct `List<RaftNode>` references |
| Log append + quorum | Y | Partial | Entries replicated via direct method calls; no network |
| Log append + quorum | Y | Partial | Entries replicated via direct method calls; stale-term append now rejected |
| Log persistence | Y | N | In-memory `List<RaftLogEntry>` only |
| Heartbeat / keep-alive | Y | N | |
| Log mismatch resolution (NextIndex) | Y | N | |
@@ -587,13 +590,12 @@ MemStore has basic append/load/purge with `Dictionary<long, StoredMessage>` unde
5. **Route pooling** — single connection per peer vs Go's 3-connection pool
### JetStream (Significant Gaps)
1. **API coverage** — Only 4 of ~20 `$JS.API.*` subjects handled (STREAM.CREATE/INFO, CONSUMER.CREATE/INFO)
2. **Stream delete/update/list** — not implemented
3. **Consumer delete/list/pause** — not implemented
4. **Retention policies** — only MaxMsgs; Interest and WorkQueue retention absent
5. **FileStore scalability** — JSONL-based (not block/compressed/encrypted)
6. **RAFT persistence** — in-memory only; cluster restart loses all JetStream state
7. **Consumer delivery completeness** — DeliverPolicy, AckPolicy.All, MaxAckPending, heartbeats, flow control absent
1. **API coverage is expanded but still incomplete** — core stream/consumer/direct/control routes are implemented, but full Go surface and edge semantics remain
2. **Policy/runtime semantics are incomplete** — retention/discard/delivery/replay models exist, but behavior does not yet match Go across all cases
3. **Snapshot/restore and cluster control are skeletal** — request/response contracts exist; durable/distributed semantics remain limited
4. **FileStore scalability** — JSONL-based (not block/compressed/encrypted)
5. **RAFT persistence and transport** — in-memory coordination; no durable log/RPC transport parity
6. **Consumer delivery completeness** — MaxAckPending, flow control, replay/backoff, and full fetch/ack lifecycle parity still incomplete
### Lower Priority
1. **Dynamic buffer sizing** — delegated to Pipe, less optimized for long-lived connections
@@ -604,7 +606,7 @@ MemStore has basic append/load/purge with `Dictionary<long, StoredMessage>` unde
---
## 10. JetStream Remaining Parity (2026-02-23)
## 13. JetStream Remaining Parity (2026-02-23)
### Newly Ported API Families
- `$JS.API.INFO`