Skip to main content

Queue

Struct Queue 

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

The app’s queue: publish here, claim from here.

Cloning is cheap — the DatabaseConnection inside is a pooled handle — so every worker holds one.

Implementations§

Source§

impl Queue

Source

pub fn new(db: &Db, app: &App) -> Self

The queue for an app. Never fails and is never optional: publish works in an app whose main.toml says nothing about queues, because the table is a built-in and a message with no subscriber is still worth recording.

Source

pub fn config(&self) -> &QueuesConfig

Source

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

Every topic this app subscribes to.

Source

pub async fn prepare(&self) -> Result<(), QueueError>

Add the index the claim query needs, if it isn’t there.

Not left to the migrator: the migrator’s job is to make columns match the resource declarations, and this index is not a property of the schema but of one query — the (status, available_at) lookup every subscriber runs on every sweep, which is a sequential scan of the whole ledger without it. Retention keeps that table small in a healthy app and large in exactly the app that is having a bad day.

Source

pub async fn publish( &self, topic: &str, message: &Value, published_by: &str, ) -> Result<Publication, QueueError>

Publish a message: one row per subscriber, then one notification.

The order matters and is not an accident. The rows are committed first, so a subscriber woken by the notification always finds them; notifying first would race, and the loser would be a wakeup for work that isn’t visible yet — which looks exactly like a queue that randomly adds 30 seconds of latency.

Source

pub async fn claim(&self, worker: &str) -> Result<Vec<Delivery>, QueueError>

Take up to [queues] batch messages for this app’s topics.

One statement, and that is the point: the SELECT … FOR UPDATE SKIP LOCKED runs inside the UPDATE’s own transaction, so the rows are claimed and the locks released in a single commit. Holding a transaction open across the handler instead would mean one database connection tied up per in-flight message, and a long handler blocking VACUUM on the whole table.

The running rows a dead worker left behind are swept back in by Queue::reclaim rather than here, so a stuck message costs a lease rather than being invisible.

Source

pub async fn next_due(&self) -> Result<Option<u64>, QueueError>

Seconds until the next scheduled message becomes claimable, if there is one waiting.

This is what makes a retry honour the backoff it was given rather than the poll interval. A failure schedules itself for now() + 10s, but nothing publishes when a backoff expires — there is no NOTIFY for “a timer went off” — so a subscriber that always waited the full poll_secs would round every retry up to the next 30-second boundary. Asking the database when to come back costs one indexed query per cycle and makes the configured number mean what it says.

None means nothing is scheduled, and the caller should wait its full interval. Some(0) means something is due now.

Source

pub async fn complete(&self, id: &str) -> Result<(), QueueError>

Mark a message handled.

Source

pub async fn fail( &self, delivery: &Delivery, error: &str, ) -> Result<bool, QueueError>

Record a failed attempt: schedule the retry, or give up.

Giving up leaves the row failed with its error rather than deleting it. A dead-letter you have to go and look at is the point — a queue that quietly discards what it could not handle is a queue that loses orders.

Source

pub async fn reclaim(&self) -> Result<u64, QueueError>

Offer up messages whose handler never came back.

Returns how many were taken back. The attempt is not undone: a handler that reliably kills its process — the classic out-of-memory loop — has spent an attempt, and will run out of them and land in the dead-letter instead of retrying until somebody notices the restart count.

Source

pub async fn prune(&self) -> Result<u64, QueueError>

Delete handled messages older than [queues] retain_hours. 0 keeps them forever.

Only done rows. A failed row is the whole reason the ledger exists and is never swept — if it were, the dead-letter would empty itself overnight and the evidence would go with it.

Source

pub async fn execute( &self, request: &str, published_by: &str, ) -> Result<Value, QueueError>

Run one operation on behalf of a function. The JSON surface behind HostApi::publish.

Trait Implementations§

Source§

impl Clone for Queue

Source§

fn clone(&self) -> Queue

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 Queue

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Queue

§

impl !UnwindSafe for Queue

§

impl Freeze for Queue

§

impl Send for Queue

§

impl Sync for Queue

§

impl Unpin for Queue

§

impl UnsafeUnpin for Queue

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

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