pub struct ActivityEventPublisher { /* private fields */ }Expand description
The durable transcript sequencer + live fan-out for one deployment.
Cloneable: the broadcast sender and the store handle are shared, so every
clone sequences into the same O keyspace and fans out to the same live
subscribers. The store is the single source of store_seq monotonicity; the
broadcast is best-effort live tail only.
Implementations§
Source§impl ActivityEventPublisher
impl ActivityEventPublisher
Sourcepub fn new(store: Arc<dyn ObservabilityStore>, capacity: NonZeroUsize) -> Self
pub fn new(store: Arc<dyn ObservabilityStore>, capacity: NonZeroUsize) -> Self
Build a publisher over store with a live broadcast of capacity.
capacity is the bounded live-tail buffer; a subscriber that lags beyond
it receives one typed TranscriptStreamLagged then re-resumes from the
durable tail. It must be non-zero (validated by the caller’s config).
Sourcepub async fn publish(
&self,
event: &ActivityEvent,
) -> Result<Option<u64>, StoreError>
pub async fn publish( &self, event: &ActivityEvent, ) -> Result<Option<u64>, StoreError>
Sequence + persist + fan out one event.
Ephemeral events are fanned out live with store_seq: None and are NEVER
persisted. Non-ephemeral events are appended to the O keyspace under the
commit-allocated store_seq (via the read-head -> append(expected_seq) ->
on-conflict-re-read-head-and-retry loop), then fanned out carrying that
store_seq. Returns the assigned store_seq for a persisted event, or
None for an ephemeral one.
A send with no live subscribers is not an error (the calm no-dashboard case); the durable append is the primary artifact.
§Errors
A StoreError from the durable append (after exhausting the retry
budget on pathological contention, or any non-conflict backend error).
Sourcepub async fn replay_from(
&self,
key: &ActivityStreamKey,
from_seq: u64,
) -> Result<Vec<ActivityRecord>, StoreError>
pub async fn replay_from( &self, key: &ActivityStreamKey, from_seq: u64, ) -> Result<Vec<ActivityRecord>, StoreError>
Read the durable O tail for key with store_seq >= from_seq.
The priming read a resuming transcript client replays before splicing onto
the live stream. from_seq = 0 replays the whole persisted transcript.
§Errors
A StoreError from the durable read.
Sourcepub async fn list_streams(
&self,
workflow_id: &WorkflowId,
run_id: &RunId,
) -> Result<Vec<ActivityStreamSummary>, StoreError>
pub async fn list_streams( &self, workflow_id: &WorkflowId, run_id: &RunId, ) -> Result<Vec<ActivityStreamSummary>, StoreError>
Enumerate the retained transcript streams of ONE RUN of workflow_id
from the durable O keyspace (empty for a run with none — old runs
simply have no retained transcript).
The run is required, never an optional filter: a workflow-wide enumeration over a continue-as-new chain would list several generations’ streams under coordinates that collide pairwise, and the caller could not tell them apart.
§Errors
A StoreError from the durable enumeration.
Sourcepub fn subscribe(
&self,
key: ActivityStreamKey,
after_seq: Option<u64>,
) -> BoxStream<'static, Result<ActivityEvent, TranscriptStreamLagged>>
pub fn subscribe( &self, key: ActivityStreamKey, after_seq: Option<u64>, ) -> BoxStream<'static, Result<ActivityEvent, TranscriptStreamLagged>>
Subscribe to the live transcript tail for key, suppressing every event
for a DIFFERENT stream and every persisted event already covered by the
resume cursor.
The broadcast is deployment-wide (one channel), so this filters to key’s
(workflow, run, activity, attempt) stream — an event from a sibling
continue-as-new generation of the same workflow fails the key comparison
and is suppressed, exactly like a different attempt’s.
after_seq dedups the splice seam
exactly like the cluster channel: attach this receiver BEFORE reading the
priming Self::replay_from tail, so an event that races the priming read
is retained by the receiver and applied after it (deduped on store_seq).
The cursor is an Option because store_seq is 0-based (the first
event is store_seq == 0): after_seq = None is a FRESH subscriber that
has applied nothing and must see every event including store_seq == 0;
after_seq = Some(n) has already applied through store_seq == n, so
events with store_seq <= n are suppressed at the seam. Ephemeral events
(which carry store_seq: None) for key are ALWAYS forwarded live — they
have no sequence to dedup and are never replayed.
Trait Implementations§
Source§impl Clone for ActivityEventPublisher
impl Clone for ActivityEventPublisher
Source§fn clone(&self) -> ActivityEventPublisher
fn clone(&self) -> ActivityEventPublisher
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for ActivityEventPublisher
impl !UnwindSafe for ActivityEventPublisher
impl Freeze for ActivityEventPublisher
impl Send for ActivityEventPublisher
impl Sync for ActivityEventPublisher
impl Unpin for ActivityEventPublisher
impl UnsafeUnpin for ActivityEventPublisher
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request