pub struct Subscription { /* private fields */ }Expand description
A handle to one subscription — owns the receive end of the bus channel.
Drop unsubscribes from everything automatically. While the handle is
alive, recv / recv_timeout /
try_recv drain queued PubsubEvents in arrival
order.
Threading. Subscription is Send + Sync —
Arc<Subscription> works, so multiple async tasks (or
spawn_blocking jobs) can share one subscription and call recv
concurrently. The underlying std::sync::mpsc::Receiver is
!Sync, so we wrap it (and the matching ack Sender) in a Mutex;
concurrent recv callers serialise on that lock, with each call
receiving a different frame in arrival order (single-consumer
semantics — NOT broadcast fanout). try_recv is non-blocking even
under contention: if the lock is held by a blocking recv,
try_recv returns Ok(None) rather than waiting.
If you need broadcast fanout (every subscriber sees every message),
open a separate Subscription per consumer — they’re cheap.
use kevy_embedded::{Config, PubsubEvent, Store};
let s = Store::open(Config::default())?;
let sub = s.subscribe(&[b"news"]);
// the subscribe ack is queued first
assert!(matches!(sub.recv()?, PubsubEvent::Subscribe { count: 1, .. }));
assert_eq!(s.publish(b"news", b"hello"), 1, "one subscriber received it");
let PubsubEvent::Message { channel, payload } = sub.recv()? else {
panic!("a publish arrives as a message");
};
assert_eq!((channel, payload), (b"news".to_vec(), b"hello".to_vec()));
drop(sub); // unsubscribes
assert_eq!(s.publish(b"news", b"again"), 0);Implementations§
Source§impl Subscription
impl Subscription
Sourcepub fn subscribe(&mut self, channels: &[&[u8]])
pub fn subscribe(&mut self, channels: &[&[u8]])
SUBSCRIBE channel [channel ...]. Per-channel Subscribe acks are
enqueued onto the receive queue in order.
Sourcepub fn psubscribe(&mut self, patterns: &[&[u8]])
pub fn psubscribe(&mut self, patterns: &[&[u8]])
PSUBSCRIBE pattern [pattern ...]. Patterns use Redis glob syntax
(*, ?, [abc]).
Sourcepub fn unsubscribe(&mut self, channels: &[&[u8]])
pub fn unsubscribe(&mut self, channels: &[&[u8]])
UNSUBSCRIBE [channel ...]. Empty channels removes every channel
subscription this handle holds (matching the Redis wire shape:
individual ack frames for each channel that was actually removed,
or a single Unsubscribe { channel: None } if none were held).
Sourcepub fn punsubscribe(&mut self, patterns: &[&[u8]])
pub fn punsubscribe(&mut self, patterns: &[&[u8]])
PUNSUBSCRIBE [pattern ...]. Empty patterns removes every pattern.
Sourcepub fn recv(&self) -> KevyResult<PubsubEvent>
pub fn recv(&self) -> KevyResult<PubsubEvent>
Block until one frame is queued. Err(io::ErrorKind::UnexpectedEof)
once the underlying bus tears down (last Store clone dropped).
Acquires the receiver mutex for the entire blocking wait — other
recv/recv_timeout callers serialise behind this one. Concurrent
try_recv calls return Ok(None) while a recv is blocked (no
wait on the lock); see the type-level doc for the trade-off.
Sourcepub fn recv_timeout(&self, dur: Duration) -> KevyResult<PubsubEvent>
pub fn recv_timeout(&self, dur: Duration) -> KevyResult<PubsubEvent>
Bounded blocking recv. Err(KevyError::TimedOut) when dur
elapses; Err(KevyError::Closed) when the bus is gone.
Sourcepub fn try_recv(&self) -> KevyResult<Option<PubsubEvent>>
pub fn try_recv(&self) -> KevyResult<Option<PubsubEvent>>
Non-blocking recv. Ok(None) if the queue is empty;
Err(KevyError::Closed) when the bus is gone.
Uses try_lock so a concurrent blocking recv doesn’t make
try_recv itself block — lock contention is reported as Ok(None)
(semantically: “no frame available right now”). Same shape callers
already handle for an empty queue.