alkstore 0.1.0

The alkstore contract crate: one reactive store trait surface — notify, streams, durable queues, TTL locks, outbox, scheduler — implemented by the alkstore-sqlite/-postgres/-mem engine crates; no driver dependencies
Documentation
//! The queue mechanism handle (ADR-019 §1, §2; ADR-010 §1–§5).
//!
//! Claim/maintenance ops live on the queue-scoped handle — placement
//! mirroring the honker-rs starting artifact. There is deliberately no
//! `claim_tx`: a claim's visibility deadline must not be tied to a
//! business transaction's lifetime (ADR-019 §1).

use serde_json::Value;

use crate::Result;
use crate::future::BoxedFuture;
use crate::job::Job;
use crate::job_handle::JobHandle;
use crate::opts::EnqueueOpts;

/// The queue-scoped handle: enqueue, claims, and maintenance ops for
/// one queue name.
///
/// Queues are names, not registered objects: the handle carries the
/// name (validated at the constructor — shared-namespace rules) and
/// the `QueueOpts` stamps resolve per enqueue, never against a live
/// registry (ADR-010 §3a).
pub trait Queue: Send + Sync {
    /// The queue name the handle was constructed with.
    fn name(&self) -> &str;

    /// Enqueue a job (auto-commit; each op atomic alone) with the
    /// handle's `QueueOpts` stamping the row (ADR-020 §3: the one
    /// handle-carrying shape resolves over this handle's opts).
    fn enqueue<'a>(&'a self, payload: Value, opts: EnqueueOpts) -> BoxedFuture<'a, Result<i64>>;

    /// Claim one claimable row — exactly-once handout under
    /// concurrency; `None` = no work (a value, not an error).
    /// Claim ordering: `priority` DESC, then ready-time, then enqueue
    /// order (ADR-010 §1). `worker_id` is the claimant identity —
    /// consumer-local, non-empty only (`InvalidName`).
    fn claim_one<'a>(
        &'a self,
        worker_id: &str,
    ) -> BoxedFuture<'a, Result<Option<Box<dyn JobHandle>>>>;

    /// Claim up to `n` rows, same ordering and exclusivity as
    /// [`Queue::claim_one`]. `worker_id` is consumer-local, non-empty
    /// only (`InvalidName`). `n` is an extent argument (ADR-023 §2):
    /// `n <= 0` claims nothing — the empty `Vec`, a value (never an
    /// error, never the whole queue).
    fn claim_batch<'a>(
        &'a self,
        worker_id: &str,
        n: i64,
    ) -> BoxedFuture<'a, Result<Vec<Box<dyn JobHandle>>>>;

    /// Batch ack: applies the uniform validity predicate per id
    /// (processing state + unexpired claim deadline); lapsed,
    /// non-claimed, acked-elsewhere, or cancelled ids silently not
    /// counted. Returns the count that landed; partial success is
    /// ordinary (ADR-010 §1).
    fn ack_batch<'a>(&'a self, ids: &[i64]) -> BoxedFuture<'a, Result<i64>>;

    /// Unconditionally delete a row in either `pending` or
    /// `processing`, regardless of which worker holds it. Not an
    /// interrupt — the holder's next handle op returns `false`, the
    /// same shape as deadline expiry. `false` = no such live row.
    fn cancel<'a>(&'a self, job_id: i64) -> BoxedFuture<'a, Result<bool>>;

    /// Get a job row — sees dead rows too (with `last_error`/
    /// `died_at`; ADR-010 §4). A pure data read: the returned `Job`
    /// carries no ops (no ghost handles; a claim's `Box<dyn JobHandle>`
    /// is the only ops carrier, ADR-019 §3).
    fn get_job<'a>(&'a self, job_id: i64) -> BoxedFuture<'a, Result<Option<Job>>>;

    /// Sweep this queue: move every past-`expires_at` row (any state —
    /// pending and processing alike, the no-stranded-rows property,
    /// ADR-010 §5) to dead, and delete dead rows past their retention
    /// stamp. Returns the count moved. No leader lock required.
    fn sweep_expired<'a>(&'a self) -> BoxedFuture<'a, Result<i64>>;
}