Skip to content

[PureGo] Generalize stream durability model - #682

Open
zlata-stefanovic-db wants to merge 2 commits into
mainfrom
purego-stream-durability-model
Open

[PureGo] Generalize stream durability model#682
zlata-stefanovic-db wants to merge 2 commits into
mainfrom
purego-stream-durability-model

Conversation

@zlata-stefanovic-db

@zlata-stefanovic-db zlata-stefanovic-db commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Generalizes the internal stream core so one implementation can serve both the existing atomic protocols (Protocol Buffers, JSON) and a future record-count protocol, with no public API change.

  • Durability units — acknowledgments are tracked as cumulative unit counts over submitted ranges rather than one ack per item, so a protocol can acknowledge part of a batch.
  • Partial replay slicing — on reconnect, only the unacknowledged suffix of a partially acknowledged item is replayed.
  • Submission receipts — a transport can report how much of a multi-frame send actually reached the server, so a failure part-way through a batch keeps the acknowledged prefix instead of discarding it.
  • Extension seamsEncoderHooks, AckModelHooks, OpenFunc, and an exported WireStream let a protocol instantiate the core over its own payload type.

Atomic proto/JSON behavior is unchanged: those encoders report one unit per item, never produce partial acknowledgments, and continue to resolve wire offsets through the existing path.

Behavior fixes found while reviewing this change

  • An acknowledgment that arrives while its Send is still outstanding, where that Send then fails, is no longer converted into a non-retryable protocol error. The core cannot know how much of that send reached the server, which is not a server violation — so the unusable ack is discarded and the retryable send failure drives recovery. Without this, a transient failure killed the stream permanently instead of reconnecting, and blamed the server for a violation it never committed.
  • Rejecting an impossible submission receipt now also clears the buffered-ack state. Otherwise teardown waits forever for a completion event that was already consumed, hanging the receiver, the supervisor, and every Close()/Terminate() caller.
  • Durable progress inside a large item refreshes its lack-of-ack budget, so a batch needing longer than one timeout to acknowledge is not torn down while the server is demonstrably alive. A duplicate or stale partial still makes no progress, so a stalled server cannot postpone recovery.
  • An acknowledgment that advances the watermark but resolves to no offset (landing in a gap below every submitted range) is rejected rather than silently raising the connection's ack watermark with no durable progress behind it.

Test plan

  • cd purego && go test -race ./...
  • cd purego && go test -count=12 -race ./internal/stream — no flakiness in the new timing-sensitive tests
  • cd purego && go vet ./... and gofmt -l clean
  • deadcode ./... reports nothing

durability_model_test.go exercises the new generic seam through a protocol-neutral row-based fake: unit-resolution table cases, partial acks, replay of only the unacknowledged remainder, receipt-preserved prefix acks, and hook validation. The two correctness fixes above have regression guards that were each confirmed to fail beforehand — the recovery guard passes against the pre-change core but failed against this branch, and the teardown guard hangs to the test timeout without its fix.

Notes

  • No public API change and no Arrow dependency. This is the generic-core foundation for the PureGo Arrow Flight path, split out so it can be reviewed on its own.
  • No NEXT_CHANGELOG.md entry: the change is confined to purego/internal/. Partial acknowledgments and submission receipts are unreachable for the shipping proto/JSON protocols, and the recovery fix restores behavior main already has, so there is no user-visible difference relative to main.
  • Now based directly on main. It was previously stacked on purego-descriptor-cache-lifecycle, which was closed without merging.

@zlata-stefanovic-db zlata-stefanovic-db self-assigned this Aug 6, 2026
@zlata-stefanovic-db
zlata-stefanovic-db changed the base branch from purego-descriptor-cache-lifecycle to main August 10, 2026 14:38
Add protocol-neutral unit-count acknowledgments, partial replay slicing,
and submission receipts while preserving atomic proto and JSON behavior.

Signed-off-by: Zlata Stefanovic <zlata.stefanovic@databricks.com>
@zlata-stefanovic-db
zlata-stefanovic-db force-pushed the purego-stream-durability-model branch from 355d04d to dec7d80 Compare August 10, 2026 15:27
@zlata-stefanovic-db
zlata-stefanovic-db marked this pull request as ready for review August 10, 2026 15:49
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