Skip to main content

KinesisStream

Struct KinesisStream 

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

A subscription descriptor for one Kinesis stream.

Every shard resumes from its stored checkpoint, and a shard without one starts at the tip (a child whose parent was read to its end starts at its own beginning). To open somewhere else, wrap the descriptor in the framework’s start_at(..) clause with a KinesisPosition.

A string literal names a stream too: #[subscriber("orders")] builds this descriptor with its defaults. An invalid descriptor (an empty stream name, a zero shard count) fails the mount before any I/O, and a stream the service does not have fails it when the subscription opens, unless the descriptor creates it.

The subscription lists the stream’s shards and lists them again as splits and merges change the set, takes a lease per shard, and runs one reader per shard it holds. A child of a split or a merge starts only after its parents are fully consumed, which keeps per-key ordering across resharding.

A broker reads a stream through one subscription: a second subscription to the same stream on one broker is refused when it opens. A second KinesisBroker with a lease store of its own reads the stream again. A KPL-aggregated record is reported as KinesisError::AggregatedRecord.

Implements SubscriptionSource, so it can sit inline in the #[subscriber(..)] decorator, and IntoSource, so the manual path’s subscriber constructor names a stream with it too:

use std::error::Error;
use std::time::Duration;

use ruststream::prelude::*;
use ruststream_kinesis::{KinesisBroker, KinesisStream};
use schemars::JsonSchema;
use serde::Deserialize;

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

struct Audit;

impl Handle<Order> for Audit {
    async fn handle(
        &self,
        order: &Order,
        _outs: &(),
        _ctx: &mut Context<'_>,
    ) -> Result<(), HandlerOutcome> {
        tracing::info!(order.id, "audited");
        Ok(())
    }
}

pub async fn run() -> Result<(), Box<dyn Error>> {
    let orders = KinesisStream::new("orders").poll_interval(Duration::from_millis(500));
    RustStream::new(AppInfo::new("orders", "0.1.0"))
        .with_broker(KinesisBroker::new(), |b| {
            b.include(subscriber(orders, Audit).build());
        })
        .run()
        .await?;
    Ok(())
}

Implementations§

Source§

impl KinesisStream

Source

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

Names the stream by its name, which is also the stream half of every LeaseKey the subscription’s shards are leased under.

A stream is named by its name; every call the subscription makes passes it as the stream name.

Source

pub fn poll_interval(self, interval: Duration) -> Self

The pause between reads on an idle shard. Defaults to 1 second, the service’s own recommendation; lower values spend the 5-reads-per-second budget faster.

Source

pub fn create_if_missing(self, shards: i32) -> Self

Creates the stream with shards provisioned shards on subscribe when it does not exist yet, then waits up to a minute for it to become active. Meant for local development and tests; production streams are usually managed as infrastructure.

Without it a stream the service does not have refuses the subscription when it opens, so the name is checked while a service is starting rather than after it has started.

Source

pub fn stream(&self) -> &str

The stream name this descriptor resolves.

Trait Implementations§

Source§

impl Clone for KinesisStream

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 KinesisStream

Source§

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

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

impl Eq for KinesisStream

Source§

impl IntoSource for KinesisStream

The manual path’s constructor takes a subject string or a source, and this is what makes the crate’s own descriptor the second: a service without the macros feature names its stream, and the settings that price a read, exactly as an attribute one does.

Source§

type Source = KinesisStream

The source the constructor stores.
Source§

fn into_source(self) -> Self

Builds the source.
Source§

impl PartialEq for KinesisStream

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 RedeliveryAddressed<ConnectedKinesisBroker> for KinesisStream

Source§

fn redelivery_address( &self, _connected: &ConnectedKinesisBroker, ) -> impl Future<Output = Result<RedeliveryAddress, KinesisError>> + Send

The stream this descriptor names, which is where a deferred copy and a spent delivery of this registration are published.

The copy keeps the record’s partition key and lands on that key’s shard, at the tip rather than in the place the original held, so a deferred record loses its position in the stream’s order. Where that order matters, declare no cap and let HandlerOutcome::retry() hold the shard: the checkpoint stops at the record, and the shard is read again from it.

max_attempts(n) counts the first delivery, and under it HandlerOutcome::retry() becomes a published copy as well, because only a copy carries the attempt count forward. dead_letter(name) is the stream a spent record leaves for, payload and headers as it arrived; a cap declared without one checkpoints past the spent record, as drop() does.

§Examples
use std::time::Duration;

use ruststream_kinesis::prelude::*;
use serde::Deserialize;

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

/// Asks for a pause when the order cannot be settled yet, and counts nothing: how many pauses
/// it gets is the mount site's to say.
#[subscriber(KinesisStream::new("orders"))]
async fn reconcile(order: &Order) -> HandlerOutcome {
    if order.id.is_multiple_of(2) {
        HandlerOutcome::ack()
    } else {
        HandlerOutcome::retry_after(Duration::from_secs(30))
    }
}

#[ruststream::app]
fn app() -> impl App {
    RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(KinesisBroker::new(), |b| {
        // Four deliveries per order, then the record leaves for a stream an operator reads.
        b.include(reconcile)
            .max_attempts(nonzero!(4))
            .dead_letter("orders.unsettled");
    })
}
Source§

impl StructuralPartialEq for KinesisStream

Source§

impl SubscriptionSource<ConnectedKinesisBroker> for KinesisStream

Source§

type Copies = AddressedCopies

Kinesis moves nothing on its own: it holds no redelivery timer, no delivery counter and no dead-letter mechanism, so the framework publishes every copy. A stream is what a subscription reads and what a publish writes to, so this descriptor knows where a copy goes.

Source§

type Subscriber = KinesisSubscriber

The subscriber type this source opens.
Source§

fn name(&self) -> &str

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

async fn subscribe( self, connected: &ConnectedKinesisBroker, ) -> Result<KinesisSubscriber, KinesisError>

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

fn channel_bindings(&self) -> Bindings

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

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

Takes the registration’s retry declaration into the descriptor, before the subscription opens. 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 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<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

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> 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<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

Source§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
Source§

impl<T> PublishedThrough<DefaultSlot> for T

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