Skip to main content

GooglePubSub

Struct GooglePubSub 

Source
pub struct GooglePubSub { /* private fields */ }
Expand description

A subscription descriptor for one Pub/Sub subscription.

Implements SubscriptionSource for the connected broker, so it sits inline in the #[subscriber(..)] decorator, and the declaration a service ships is the one its tests run:

use std::time::Duration;

use ruststream_gcp_pubsub::prelude::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Order {
    id: u64,
}

#[subscriber(
    GooglePubSub::new("orders-workers")
        .max_outstanding(1_000)
        .ack_extension(Duration::from_secs(60))
)]
async fn handle(order: &Order) -> HandlerOutcome {
    tracing::info!(order.id, "accepted");
    HandlerOutcome::ack()
}

#[ruststream::app]
fn app() -> impl App {
    RustStream::new(AppInfo::new("orders", "0.1.0"))
        .with_broker(PubSubBroker::new("my-project"), |b| {
            b.include(handle);
        })
}

Implementations§

Source§

impl GooglePubSub

Source

pub fn new(name: impl Into<String>) -> Self

Names an existing subscription (short name or full projects/{p}/subscriptions/{s} resource name).

The name is taken on trust: nothing is created, and the subscription is infrastructure this crate does not own. Where it answers to nothing, the streaming pull is what says so, and the stream yields PubSubError::Receive naming the subscription instead of delivering.

Source

pub fn create_with_topic(self, topic: impl Into<String>) -> Self

Creates the subscription bound to topic on subscribe when it does not exist yet (the topic is created too). Meant for local development and tests against the emulator; production subscriptions are usually managed as infrastructure.

The subscription it creates enables message ordering, so a run of messages sharing an ordering key reaches the handler in publish order. A subscription that already exists keeps whatever its own configuration says: ordered delivery is a field of the subscription resource, and the crate does not change it on a subscription it did not create.

Source

pub fn max_outstanding(self, messages: i64) -> Self

Flow control: how many received messages may be outstanding (unacked) at once. Defaults to the client’s 1000.

The limit travels with the streaming pull and the service is what holds to it, pausing the stream while this many deliveries are unsettled and resuming below it.

Source

pub fn ack_extension(self, extension: Duration) -> Self

How far each background ack-deadline extension reaches while a handler runs. The client clamps it to the protocol’s 10s..=600s range; defaults to 60s.

Source

pub fn max_lease(self, lease: Duration) -> Self

How long one delivery may stay unsettled before the client stops extending its ack deadline. Defaults to the client’s own hour.

This is the budget a delayed retry spends: HandlerOutcome::retry_after(delay) holds the delivery in the process for delay, and a delay longer than this is refused at the call, because the subscription would redeliver before it elapsed.

use std::time::Duration;

use ruststream_gcp_pubsub::prelude::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Invoice {
    id: u64,
    ready: bool,
}

/// An invoice that is not ready yet comes back in ninety minutes, inside the lease.
#[subscriber(
    GooglePubSub::new("invoices-workers").max_lease(Duration::from_hours(2))
)]
async fn send(invoice: &Invoice) -> HandlerOutcome {
    if !invoice.ready {
        return HandlerOutcome::retry_after(Duration::from_mins(90));
    }
    tracing::info!(invoice.id, "sent");
    HandlerOutcome::ack()
}

#[ruststream::app]
fn app() -> impl App {
    RustStream::new(AppInfo::new("invoices", "0.1.0"))
        .with_broker(PubSubBroker::new("my-project"), |b| {
            b.include(send);
        })
}
Source

pub fn batch_wait(self, wait: Duration) -> Self

How long a partial batch waits for more deliveries after its first one, for a handler that takes a slice. Defaults to 50ms.

How large a batch may be is not named here: that is the registration’s batch(n), which reaches the subscription on its own. This is the other half - how long the subscription is willing to wait for a batch that size, before handing over what it has.

use std::time::Duration;

use ruststream_gcp_pubsub::prelude::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Order {
    id: u64,
}

#[subscriber(GooglePubSub::new("orders-workers").batch_wait(Duration::from_millis(200)))]
async fn index(orders: &[Order]) -> HandlerOutcome {
    let ids: Vec<u64> = orders.iter().map(|order| order.id).collect();
    tracing::info!(?ids, "indexed");
    HandlerOutcome::ack()
}

#[ruststream::app]
fn app() -> impl App {
    RustStream::new(AppInfo::new("orders", "0.1.0"))
        .with_broker(PubSubBroker::new("my-project"), |b| {
            // Up to 100 orders per call, or whatever arrived within 200ms of the first.
            b.include(index.batch(nonzero!(100)));
        })
}
Source

pub fn subscription(&self) -> &str

The subscription name this descriptor resolves.

Trait Implementations§

Source§

impl Clone for GooglePubSub

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 Debug for GooglePubSub

Source§

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

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

impl Eq for GooglePubSub

Source§

impl FromName for GooglePubSub

A subscription is identified by its name and nothing else, every other setting having a default, so the mount site may supply the name instead of the declaration: #[subscriber(GooglePubSub)] on the handler and .name("orders-workers") where it is mounted.

§Examples

use ruststream_gcp_pubsub::prelude::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Order {
    id: u64,
}

#[subscriber(GooglePubSub)]
async fn handle(order: &Order) -> HandlerOutcome {
    tracing::info!(order.id, "accepted");
    HandlerOutcome::ack()
}

#[ruststream::app]
fn app() -> impl App {
    RustStream::new(AppInfo::new("orders", "0.1.0"))
        .with_broker(PubSubBroker::new("my-project"), |b| {
            // The deployment names the subscription; every other setting is the default.
            b.include(handle.name("orders-workers"));
        })
}
Source§

fn from_name(name: impl Into<Cow<'static, str>>) -> Self

Builds the source bound to name.
Source§

impl IntoSource for GooglePubSub

Source§

type Source = GooglePubSub

The source the constructor stores.
Source§

fn into_source(self) -> Self

Builds the source.
Source§

impl PartialEq for GooglePubSub

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for GooglePubSub

Source§

impl SubscriptionSource<ConnectedPubSubBroker> for GooglePubSub

A Pub/Sub subscription moves a spent delivery itself, so the copy path is BrokerMoves: the subscription’s dead-letter policy is the mechanism, and nothing is published from the service to retry a message. .out_retry(..) over this descriptor is therefore a compile error, and the error names it.

§Examples

.max_attempts(n).dead_letter(topic) at the mount site becomes the subscription’s own dead-letter policy, written when the service starts:

use std::time::Duration;

use ruststream_gcp_pubsub::prelude::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Payment {
    id: u64,
    settled: bool,
}

#[subscriber(GooglePubSub::new("payments-workers").batch_wait(Duration::from_millis(200)))]
async fn reconcile(payments: &[Payment]) -> HandlerOutcome {
    if payments.iter().any(|payment| !payment.settled) {
        return HandlerOutcome::retry_after(Duration::from_secs(5));
    }
    tracing::info!(count = payments.len(), "settled");
    HandlerOutcome::ack()
}

#[ruststream::app]
fn app() -> impl App {
    RustStream::new(AppInfo::new("payments", "0.1.0")).with_broker(
        PubSubBroker::new("my-project"),
        |b| {
            // Pub/Sub gives one payment five deliveries, then publishes it to `payments-dead`.
            b.include(reconcile.batch(nonzero!(50)))
                .max_attempts(nonzero!(5u32))
                .dead_letter("payments-dead");
        },
    )
}
Source§

fn declare_retry(self, declaration: &RetryDeclaration) -> Self

Takes in the registration’s cap and dead-letter destination, which become the subscription’s dead-letter policy when subscribe opens it: the topic is the policy’s deadLetterTopic and the cap its maxDeliveryAttempts.

Only recorded here. The declaration turns into topology where the connection exists, and a half declaration is refused there rather than opening a subscription that honours neither half.

Source§

type Subscriber = PubSubSubscriber

The subscriber type this source opens.
Source§

type Copies = BrokerMoves

Who publishes the copies this subscription’s retries are made of, and who names where they go: AddressedCopies, NamedCopies or BrokerMoves. Read more
Source§

fn name(&self) -> &str

The name (subject / channel) this subscription binds to. Read more
Source§

async fn subscribe( self, connected: &ConnectedPubSubBroker, ) -> Result<PubSubSubscriber, PubSubError>

Opens the subscription against the connected broker. Called once at startup. Read more
Source§

fn declare_retry_on( &self, connected: &C, declaration: &RetryDeclaration, ) -> Result<(), DeclareRetryError>

Carries the registration’s declaration to the broker, at the same point and before the subscription opens. Read more
Source§

fn channel_bindings(&self) -> Bindings

What this subscription adds to its channel in the generated AsyncAPI document. Read more
Source§

fn operation_bindings(&self) -> Bindings

What this subscription adds to its receive operation in the document. Read more
Source§

fn message_bindings(&self) -> Bindings

What this subscription adds to the messages that arrive on it. Read more

Auto Trait Implementations§

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self> ⓘ

Attaches the current Context to this type, returning a WithContext wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> PublishedThrough<DefaultSlot> for T

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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, !>

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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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