refactor(streaming)!: one streaming core, correct cursors, faster consumers #126
Labels
No labels
breaking-change
bug
documentation
duplicate
enhancement
good first issue
help wanted
performance
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/ATProto.NET#126
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of the v0.7.0 update cycle (wave 5). Firehose and Jetstream: one streaming core, correct cursors, and less CPU per event. Sync 1.1 verification builds on this in a follow-up issue.
Consolidation
FirehoseClientandJetstreamClient. This also stops a secondSubscribeAsyncleaking a socket.StreamReconnectPolicy(InitialDelay,MaxDelay,int? MaxAttempts, wherenullmeans unlimited instead of-1) on every consumer's options. When attempts run out,ConsumeAsyncthrows instead of completing normally as if the stream had ended.CursorTracker: the final save happens infinally, and commits dropped by a collection filter still advance the cursor. Today a rarely matching filter replays everything since the last match after a restart. Persist cursors off the read loop (single-flight), so a slow store doesn't stall the socket.IFirehoseCursorStore→IStreamCursorStore(withValueTaskmethods), shared by both streams. Stream clients implementIAsyncDisposable.FirehoseConsumerinto the typed consumer so each frame is parsed once; todayTryReadSeqfully re-parses every frame. Otherwise use a seq-only CBOR scan, which is 11× cheaper.TypedFirehoseConsumer:ops[].pathbefore deserializing when a collection filter is set;VerifySignatures = truewith noVerifiercurrently skips verification silently: verify exactly when a verifier is configured and delete the bool.op = -1, for exampleFutureCursorandConsumerTooSlow) as a typed error instead of dropping them.subscribeLabels: parse#labelsand#infointo typed messages. It has 0 callers today andLabelsEventis dead; the label-signing issue builds on this.JetstreamDictionaryClientfolded into the archive client;JetstreamException;JetstreamPlanStats,IsConnected,PinnedTipSeq, the no-opDispose, …).Protocol
JetstreamCursor.FromTimestamp, document v1 → v2 cursor migration, and don't dedupe timestamp seeks bytime_us.HEADsize probing (#347) and a Jetstream/xrpc/_healthhealth check.Performance
ToEvent()(5.1 µs / 11.8 KB per row today). Decode blocks in the download stage (parallel, still in order). Intern the repetitive strings per block.CHANGELOG
Breaking changes(options, the exhausted-attempts behaviour, renamed interfaces, removed types),Fixed(cursor bugs, verification skip),Added(timestamp cursors, error frames, labels stream).From #119 part 4 (#157), left to this issue:
TypedFirehoseConsumerOptions.CollectionFilteris still a set of strings.IRecordEventacross firehose and Jetstream.RepoOpActionandJetstreamOperationare separate enums with the same members; consider unifying them.docs/firehose.md"With Cursor" example readsmessage.Seqfrom a raw frame that has no such member.rev/handlebecomes null and the event is kept). Surface drops through a counter or log hook when consolidating.Also from #129:
DagCborDecoder(the shared DAG-CBOR→JSON transcoder from #111) writes$bytesvalues with base64 padding, but the atproto data model specifies base64 without padding. Fix it while consolidating the transcoder, with a pinned test.Also from #128:
chat.bsky.moderation.subscribeModEvents(an authenticated WebSocket subscription) was deferred to the consolidated streaming core. Add it here, with typed events and an unknown fallback.