pub struct RedisPublisher { /* private fields */ }Expand description
The live stream publisher: RedisPublish paired with a connection. Cheap to clone.
Publisher::publish appends the message to the stream named by
OutgoingMessage::name with XADD <name> * .... The
payload and headers are encoded as entry fields (see crate::RedisStream for the consuming
side).
A publisher may outlive the connected broker it came from (it is a handle aliasing the
connection), so every operation after
shutdown reports RedisError::ShutDown rather
than running against a closed pool.
§Transactions
Both framework transaction kinds are available on standalone and sentinel topologies, and both
commit the same way: the buffer is held client-side while the transaction is open and flushed
as one MULTI / EXEC block, in publish order, so subscribers see the whole batch or none of
it. They differ only in where that buffer lives.
- Borrowed (
TransactionalPublisher): the handle carries one transaction.begin_transactionclaims it and starts buffering published messages,commitflushes them, andabortdiscards them. Clones of a handle share the same open transaction, and a secondbegin_transactionwhile one is open is rejected. - Owned (
OwnedTransactions): everytransactioncall returns aRedisTransactionowning its own buffer, so any number can be open on one handle concurrently and the handle keeps publishing directly meanwhile.
Two Redis properties apply to both kinds. Cluster supports neither, because a MULTI block
cannot span hash slots, so opening a transaction there returns
RedisError::InvalidOptions. And Redis has no rollback: a command that fails at runtime
inside EXEC does not undo the commands before it. For a block of XADDs against stream keys
that is practically limited to out-of-memory and wrong-type keys; a command the server refuses
to queue discards the whole block.
§Examples
use ruststream::OutgoingMessage;
use ruststream_fred::stream::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Outgoing)]
struct Order {
id: u64,
}
#[subscriber("orders", reply("processed"))]
async fn process(orders: &[Order]) -> Result<Vec<Order>, HandlerOutcome> {
Ok(orders.iter().map(|order| Order { id: order.id }).collect())
}
#[ruststream::app]
fn app() -> impl App {
let broker = RedisBroker::standalone("redis://localhost:6379").default_group("workers");
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(broker, |b| {
// The borrowed kind: one batch's replies, buffered and committed as one MULTI / EXEC.
b.include(process.batch(nonzero!(32)))
.out_reply(TransactionalPublish)
.transactional();
// The owned kind, in the hook where a service makes its first publishes.
b.after_startup(TransactionalPublish, async move |publisher| {
let mut seed = publisher.transaction().await?;
seed.publish(
OutgoingMessage::new("processed", br#"{"id":0}"#.as_slice()),
None,
)
.await?;
seed.commit().await
});
})
}Trait Implementations§
Source§impl Clone for RedisPublisher
impl Clone for RedisPublisher
Source§impl Debug for RedisPublisher
impl Debug for RedisPublisher
Source§impl OwnedTransactions for RedisPublisher
Owned transactions: every transaction call opens an
independent buffer-owning RedisTransaction, so any number can be open concurrently on one
handle, next to (and unaffected by) the handle-level TransactionalPublisher transaction.
impl OwnedTransactions for RedisPublisher
Owned transactions: every transaction call opens an
independent buffer-owning RedisTransaction, so any number can be open concurrently on one
handle, next to (and unaffected by) the handle-level TransactionalPublisher transaction.
Source§fn transaction(
&self,
) -> impl Future<Output = Result<RedisTransaction, RedisError>>
fn transaction( &self, ) -> impl Future<Output = Result<RedisTransaction, RedisError>>
§Errors
Returns RedisError::InvalidOptions on a cluster topology, which cannot offer
multi-key transactions.
Source§type Transaction = RedisTransaction
type Transaction = RedisTransaction
transaction.Source§impl Publisher for RedisPublisher
impl Publisher for RedisPublisher
Source§type Payload = Take
type Payload = Take
XADD hands the body to the client as the value of a field, and the client keeps it, so
the buffer the framework wrote becomes that value.
Source§type Options = RedisPublishOptions
type Options = RedisPublishOptions
XADD takes the entry id and the trim threshold per command, and this publisher fixes
both (* and no trim); the stream key is the message’s name, not a setting. What is left
to a call site is the partition key, which leaves as an entry field like any other header.
Source§type Error = RedisError
type Error = RedisError
publish.Source§impl TransactionalPublisher for RedisPublisher
impl TransactionalPublisher for RedisPublisher
Source§fn begin_transaction(&self) -> impl Future<Output = Result<(), Self::Error>>
fn begin_transaction(&self) -> impl Future<Output = Result<(), Self::Error>>
Starts buffering published messages on this handle.
§Errors
Returns RedisError::InvalidOptions on a cluster topology, which cannot offer
multi-key transactions, or RedisError::TransactionBusy when a transaction is already
open on this handle (the open one is left untouched).
Source§async fn commit(&self) -> Result<(), Self::Error>
async fn commit(&self) -> Result<(), Self::Error>
Flushes the buffered XADDs as one MULTI / EXEC block, in publish order, then clears
the transaction.
§Errors
Returns RedisError::NoTransaction when no transaction is open on this handle,
RedisError::ShutDown when the connection is gone, or RedisError::Publish if the
block is rejected. On failure the transaction is already closed: the buffer is lost, and
recovery is redelivery of the inputs rather than resubmission of the buffer.
Auto Trait Implementations§
impl !RefUnwindSafe for RedisPublisher
impl !UnwindSafe for RedisPublisher
impl Freeze for RedisPublisher
impl Send for RedisPublisher
impl Sync for RedisPublisher
impl Unpin for RedisPublisher
impl UnsafeUnpin for RedisPublisher
Blanket Implementations§
impl<T> Bindable for Twhere
T: Publisher + Named,
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> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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 moreSource§impl<P> PublishExt for P
impl<P> PublishExt for P
Source§fn message<'a, T>(
&'a self,
value: &'a T,
) -> PublishBuilder<&'a Self, MessageBody<'a, T>, UnnamedCodec, HeadersUnset, <T as OutgoingDestination>::Form>where
T: OutgoingDestination,
fn message<'a, T>(
&'a self,
value: &'a T,
) -> PublishBuilder<&'a Self, MessageBody<'a, T>, UnnamedCodec, HeadersUnset, <T as OutgoingDestination>::Form>where
T: OutgoingDestination,
#[derive(Outgoing)] value, encoded with the crate’s
default codec (name another one with with_codec(..)). A
Serialized value’s bytes leave as they are instead - the wire is
the type’s own (MessageWire), and no codec runs on it. Read moreSource§fn begin(
&self,
) -> impl Future<Output = Result<TransactionScope<'_, Self, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + TransactionalPublisher,
fn begin(
&self,
) -> impl Future<Output = Result<TransactionScope<'_, Self, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + TransactionalPublisher,
TransactionScope that
owns it. Read moreSource§fn owned_transaction(
&self,
) -> impl Future<Output = Result<TypedTransaction<Self::Transaction, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + OwnedTransactions,
fn owned_transaction(
&self,
) -> impl Future<Output = Result<TypedTransaction<Self::Transaction, UnnamedCodec, AnyDeclared>, Self::Error>> + Sendwhere
Self: Sized + OwnedTransactions,
TypedTransaction that owns it. Read more