Problem
After the prefetch change (#383), Collector has separate fetch and ack progress. That is the right implementation for bounded read-ahead, but it makes the API easier to misuse.
Today the API still looks like this:
pub async fn next_batch(&mut self) -> Result<Option<CollectedBatch>>;
pub async fn ack(&mut self, sequence: u64) -> Result<()>;
The collector remains safe with respect to crash recovery because restart resumes from the last acked sequence, not the last fetched one. Fetched but unacked batches are replayed.
The problem is the in-process contract. Once callers can fetch ahead, completion ordering becomes an explicit part of the API, but the current interface does not help much:
- callers can fetch arbitrarily ahead unless they impose their own discipline
- callers must manage ordering themselves when work completes out of order
ack(sequence) exposes protocol details without making the ordering rules easier to follow
- a batch-shaped ack API by itself would not really fix this unless it also addresses out-of-order completion
This is not a correctness bug in the current prefetch implementation. It is an API design issue that becomes more obvious once read-ahead exists.
Possible directions
- keep strict in-order
ack() semantics and document the contract more clearly
- add collector-managed bounded read-ahead instead of leaving read-ahead behavior to the caller
- expose an API that acknowledges fetched batches rather than raw sequence numbers
- let the collector buffer out-of-order completions until earlier batches are acked
- make out-of-order completion an explicit error path with clearer ergonomics
- enforce a maximum fetch-ahead depth in the collector
- expose fetched-vs-acked depth as a metric or debug value so misuse is easier to spot
Problem
After the prefetch change (#383),
Collectorhas separate fetch and ack progress. That is the right implementation for bounded read-ahead, but it makes the API easier to misuse.Today the API still looks like this:
The collector remains safe with respect to crash recovery because restart resumes from the last acked sequence, not the last fetched one. Fetched but unacked batches are replayed.
The problem is the in-process contract. Once callers can fetch ahead, completion ordering becomes an explicit part of the API, but the current interface does not help much:
ack(sequence)exposes protocol details without making the ordering rules easier to followThis is not a correctness bug in the current prefetch implementation. It is an API design issue that becomes more obvious once read-ahead exists.
Possible directions
ack()semantics and document the contract more clearly