Skip to main content

PatternConsumer

Struct PatternConsumer 

Source
pub struct PatternConsumer<C: ConsumerApi = Consumer> { /* private fields */ }
Expand description

Regex-pattern consumer. Holds one consumer per matching topic and reconciles the set against PIP-145 deltas on update().

Generic over C: crate::ConsumerApi — defaults to the tokio runtime’s Consumer. The companion PatternConsumerBuilder<'a, E> selects the engine and produces a PatternConsumer<<E::ClientState as SubscribeApi>::Consumer> on .subscribe().

Implementations§

Source§

impl<C: ConsumerApi + Clone> PatternConsumer<C>

Source

pub fn namespace(&self) -> &str

Namespace this consumer is watching, as supplied to the builder.

Source

pub fn pattern(&self) -> &str

Regex pattern this consumer is watching, as supplied to the builder.

Source

pub fn subscription(&self) -> &str

Subscription name shared across every per-topic child.

Source

pub fn topics(&self) -> Vec<String>

Snapshot of the topics currently subscribed, in the order they were added.

Source

pub fn len(&self) -> usize

Number of underlying consumers.

Source

pub fn is_empty(&self) -> bool

true if the consumer set is empty (no topic in the namespace currently matches).

Source

pub async fn update<E>( &self, client: &PulsarClient<E>, ) -> Result<ReconcileReport, PulsarError>
where E: Engine, E::ClientState: SubscribeApi<Consumer = C> + BrokerMetadataApi,

Drain pending PIP-145 TopicListChanged deltas from the underlying connection and reconcile the consumer set: newly-added topics are subscribed, removed topics are closed and dropped.

Idempotent; returns the count of additions and removals applied during this call. Mirrors Java’s internal PatternMultiTopicsConsumerImpl#recheckTopics cycle.

PIP-145 child-subscribe routes through the engine-generic crate::ConsumerBuilder which dispatches via crate::SubscribeApi.

§Errors

Returns the first PulsarError encountered while subscribing a new topic; topics successfully reconciled before the error remain subscribed.

Source

pub async fn receive(&self) -> Result<PatternMessage, PulsarError>

Receive the next message across any currently-subscribed topic. The future is cancel-safe: dropping it leaves un-popped messages in their respective per-consumer queues.

§Errors

Returns PulsarError::Config if the consumer set is empty. Otherwise propagates the first per-topic receive error.

Source

pub async fn ack( &self, topic: &str, message_id: MessageId, ) -> Result<(), PulsarError>

Acknowledge a message. The caller supplies the topic the message came from (carried by PatternMessage::topic) so the ack routes to the right child.

§Errors

Returns PulsarError::Config if the topic is no longer in the active set (e.g. a concurrent update() removed it). Otherwise returns the child consumer’s ack error.

Source

pub async fn ack_cumulative( &self, topic: &str, message_id: MessageId, ) -> Result<(), PulsarError>

Cumulative ack on the per-topic child that produced message_id.

§Errors

See Self::ack.

Source

pub fn negative_ack( &self, topic: &str, message_id: MessageId, ) -> Result<(), PulsarError>

Negatively acknowledge a message on the per-topic child that produced it.

§Errors

Returns PulsarError::Config if the topic is no longer in the active set.

Source

pub fn redeliver_unacked(&self)

Redeliver every unacked message across every child consumer. Mirrors Java Consumer#redeliverUnacknowledgedMessages at the pattern scope.

Source

pub fn aggregate_stats(&self) -> ConsumerStats

Aggregate cumulative stats across every child consumer (issue #347). Thin wrapper over magnetar_proto::ConsumerStats::fold, and the exact analogue of crate::MultiTopicsConsumer::aggregate_stats at the pattern scope: collect each child’s (stats(), receive_latency_histogram()) snapshot — taken under the same lock acquisition so the pair is mutually consistent — and fold them per that function’s documented per-field rule. The six cumulative totals + pending_batch_acks sum; msgs_per_sec / bytes_per_sec sum as f64 (fan-in throughput); receive_latency_max_ms is the exact max; receive_latency_p50_ms / receive_latency_p99_ms are recomputed from a REAL merge of every child’s receive-latency histogram rather than summed or maxed, which is not statistically sound.

A child subscribed mid-window by PatternConsumer::update contributes a full snapshot of its counters immediately, but 0.0 to the rate fields until it has been sampled twice — the rate window needs a baseline first. Java’s MultiTopicConsumerStatsRecorderImpl behaves identically.

The rate fields are populated by the client-wide sweep armed with crate::ClientBuilder::stats_interval, which reaches every child of this subscription because it ticks each slot on the connection rather than fanning out from here (ADR-0089 — Java’s wrappers have no fan-out either). With that knob unset they stay caller-driven; see the note on magnetar_proto::consumer::ConsumerState::record_rate_window.

Source

pub fn is_connected(&self) -> bool

true while every child consumer reports the underlying connection is up.

Source

pub fn is_closed(&self) -> bool

true once every child consumer is closed.

Source

pub fn start_auto_reconcile<E>( &self, client: Arc<PulsarClient<E>>, interval: Duration, ) -> JoinHandle<()>
where E: Engine, E::ClientState: SubscribeApi<Consumer = C> + BrokerMetadataApi,

Spawn a background tokio task that drives PatternConsumer::update on a periodic ticker, mirroring Java’s PatternMultiTopicsConsumerImpl internal reconciliation timer.

The task ticks every interval, calls update(&client), swallows errors (logged at warn), and exits cleanly once PatternConsumer::is_closed returns true. The caller can also stop the loop early by calling tokio::task::JoinHandle::abort on the returned handle — the task is not stored inside the consumer, so it never outlives the caller’s intent.

The returned tokio::task::JoinHandle is detached from the consumer: dropping the consumer does not abort the task on its own, but the next tick after every child is closed will observe is_closed() and return. For deterministic teardown, abort the handle before dropping the consumer.

client is taken as Arc because the task captures it for the lifetime of the ticker loop; callers typically already hold the client behind an Arc.

Engine-generic: works under any E whose ClientState implements both crate::SubscribeApi (for child-subscribes) and crate::BrokerMetadataApi (for delta polling) — both runtimes do.

Source

pub async fn close(self) -> Result<(), PulsarError>

Close every underlying consumer. Drops the consumer set and returns the first per-child error encountered. Mirrors MultiTopicsConsumer::close semantics: best-effort teardown — every child gets a chance to close.

§Errors

Returns the first child-close error; subsequent errors are swallowed.

Trait Implementations§

Source§

impl<C: ConsumerApi> Clone for PatternConsumer<C>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<C: Debug + ConsumerApi> Debug for PatternConsumer<C>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<C> WrapperReceiver for PatternConsumer<C>
where C: ConsumerApi + Clone + Send + Sync + 'static,

Push-delivery support: a PatternConsumer drives the wrapper listener poller via its topic-fanning Self::receive. Children discovered after subscribe — when a Self::update reconciliation cycle subscribes a topic that newly matched the pattern (PIP-145 TopicListChanged) — inherit the listener: receive() re-snapshots the child set on every call, so a child added between two receive() calls is delivered on the next sweep. This mirrors Java PatternMultiTopicsConsumerImpl, where the parent owns the single listener executor and routes every child (initial or later-discovered) through it.

Source§

async fn wrapper_receive( &self, ) -> Result<(String, IncomingMessage), PulsarError>

Receive the next message across the wrapper’s current child set, returning the originating topic and the message. A terminal error (every child closed / disconnected) breaks the poller loop for a clean shutdown — the same signal ConsumerApi::receive gives the single-topic poller. On an empty set the wrapper receive() errors immediately; the poller does not treat that as terminal (see Self::is_empty) — it parks on Self::membership_changed.
Source§

fn is_empty(&self) -> bool

true when the wrapper currently holds no child consumers (e.g. a pattern consumer whose pattern matched nothing yet). The poller parks on Self::membership_changed rather than spinning on the empty-set error.
Source§

async fn membership_changed(&self)

Resolves when a child consumer is added to the set after this future was created. The poller races its in-flight Self::wrapper_receive against this so a child discovered after the poller parked (pattern TopicListChanged deltas, partition growth) is swept on the next iteration: when this wins, the poller drops the stale receive (cancel-safe — unpopped messages stay queued) and re-snapshots. No channel (ADR-0003); the underlying Notify stores one permit so an add that races a wait is not lost.

Auto Trait Implementations§

§

impl<C = Consumer> !RefUnwindSafe for PatternConsumer<C>

§

impl<C = Consumer> !UnwindSafe for PatternConsumer<C>

§

impl<C> Freeze for PatternConsumer<C>
where Arc<Inner<C>>: Freeze,

§

impl<C> Send for PatternConsumer<C>
where Arc<Inner<C>>: Send,

§

impl<C> Sync for PatternConsumer<C>
where Arc<Inner<C>>: Sync,

§

impl<C> Unpin for PatternConsumer<C>
where Arc<Inner<C>>: Unpin,

§

impl<C> UnsafeUnpin for PatternConsumer<C>
where Arc<Inner<C>>: UnsafeUnpin,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more