reliar-inbox 0.2.0

Transactional inbox deduplication: InboxStore/InboxHandler contracts, claim/complete/fail/purge semantics (no storage or transport dependency).
Documentation
//! `reliar-inbox` is the transactional inbox: dedup of inbound messages keyed
//! `(scope, message_id)`, inside the caller's own transaction (ADR 0042).
//!
//! The guarantee, stated once: **effectively-once for effects that live in the caller's
//! transaction; at-least-once for everything else; no exactly-once claim, no ordering
//! promise.** A bounded-retry dead state exists (ADR 0042 Amendment A), but it changes no
//! guarantee — it only stops a poison message from being redelivered forever.
//!
//! A provider (`reliar-store-postgres`) implements [`InboxStore`] against its own transaction
//! type; this crate depends on `reliar-core` only and names no storage engine.
//!
//! This crate cannot construct a store to run a doctest against (ADR 0043 §7 — there is no
//! in-memory fake), so the shape below is a **compiled, never-called generic function**: it
//! type-checks the real call shape and the real `InboxStore<Tx>` bound against any provider.
//! `reliar-store-postgres`'s own docs carry a runnable example over `PostgresInboxStore`.
//!
//! ```
//! # use reliar_inbox::{InboxHandler, InboxMessage, InboxOutcome, InboxScope, InboxStore};
//! #
//! struct RecordOrder;
//!
//! impl<Tx: Send> InboxHandler<Tx> for RecordOrder {
//!     type Output = ();
//!     type Error = std::convert::Infallible;
//!
//!     async fn handle(&self, _tx: &mut Tx) -> Result<Self::Output, Self::Error> {
//!         // Every write here shares the caller's transaction with the inbox completion.
//!         Ok(())
//!     }
//! }
//!
//! async fn consume<Tx: Send, S: InboxStore<Tx>>(
//!     store: &S,
//!     tx: &mut Tx,
//!     scope: &InboxScope,
//!     message: InboxMessage<'_>,
//! ) {
//!     match store.process(tx, scope, message, &RecordOrder).await {
//!         Ok(InboxOutcome::Processed(())) => { /* tx.commit(), then ack */ }
//!         Ok(_) => { /* AlreadyCompleted, InProgress or Dead: roll back, drop `tx` */ }
//!         Err(_) => { /* roll back, log, nak */ }
//!     }
//! }
//! ```

#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs)]

mod claim;
mod dead_letters;
mod error;
mod handler;
mod message;
mod purge;
mod record;
mod record_id;
mod scope;
mod store;

pub use claim::{InboxClaim, InboxFailure, InboxOutcome};
pub use dead_letters::{InboxDeadCursor, InboxDeadLetters, InboxDeadQuery};
pub use error::InboxProcessError;
pub use handler::InboxHandler;
pub use message::InboxMessage;
pub use purge::{InboxPurgeReport, InboxPurgeRequest};
pub use record::{InboxRecord, InboxRecordBuilder, InboxState};
pub use record_id::InboxRecordId;
/// Re-exported from `reliar-core`: an [`InboxStore::Error`]'s `Classify` bound and the resulting
/// `FailureKind`. New code may also name `reliar_core::` directly.
pub use reliar_core::{Classify, FailureKind};
pub use scope::{InboxScope, InboxScopeError};
pub use store::InboxStore;

#[cfg(doctest)]
mod readme_doctests;