pub struct PgStore { /* private fields */ }Expand description
The Postgres adapter. Construct it with PgStore::new around a pool YOU own —
failure classification: headgate never closes a pool it did not open, and every entry point accepts an
existing one. PgStore::connect is a convenience for tools and tests.
CONNECTION BUDGET (failure classification, live-proven in both languages/backends): store calls borrow
transiently; each in-flight TRANSACTIONAL handler (once, step_once) HOLDS one;
connect*/with_listen adds ONE dedicated LISTEN connection OUTSIDE the pool. If T
callbacks may retain transactions concurrently across every worker sharing this pool,
size the command pool at T + 2. No internal path holds one pooled connection while
acquiring another. See docs/connection-budget.md for the exact physical formula and
the user-created nested-acquisition caveat.
push wakeups push wakeup needs a dedicated LISTEN connection, which needs connection config —
so the Notifying capability exists only on stores built via connect* (or
PgStore::with_listen). A pool-only store polls, honestly.
Implementations§
Source§impl PgStore
impl PgStore
pub async fn set_archive_policy( &self, queue: &str, retention: Duration, ) -> Result<(), StoreError>
pub async fn clear_archive_policy(&self, queue: &str) -> Result<(), StoreError>
Sourcepub async fn prune_archive_month(&self, month: &str) -> Result<u64, StoreError>
pub async fn prune_archive_month(&self, month: &str) -> Result<u64, StoreError>
Truncate one closed monthly archive partition after every row’s retained audit lifetime has elapsed. A closed month cannot receive a normal store-time eviction, which makes the safety check stable until TRUNCATE takes its table lock.
pub async fn index_health(&self) -> Result<Vec<IndexHealth>, StoreError>
pub async fn reindex_concurrently(&self, name: &str) -> Result<(), StoreError>
Sourcepub fn new(pool: Pool) -> Self
pub fn new(pool: Pool) -> Self
failure classification caller-supplied pool. Never closed by this crate.
pub fn with_options(pool: Pool, opts: PgStoreOptions) -> Self
Sourcepub fn in_schema(pool: Pool, schema: &str) -> Result<Self, StoreError>
pub fn in_schema(pool: Pool, schema: &str) -> Result<Self, StoreError>
Wrap a caller-owned pool while explicitly qualifying every headgate object with
schema. The pool may be shared by stores for other schemas: no session-level
search_path state is changed or trusted.
pub fn with_options_in_schema( pool: Pool, opts: PgStoreOptions, schema: &str, ) -> Result<Self, StoreError>
Sourcepub fn schema(&self) -> Option<&str>
pub fn schema(&self) -> Option<&str>
The explicit schema configured at store construction. None is the legacy/default
connection namespace and preserves byte-identical SQL for existing callers.
Sourcepub fn with_listen(self, config: Config) -> Self
pub fn with_listen(self, config: Config) -> Self
Enable push wakeups push wakeup on a pool-constructed store by supplying connection config for the dedicated LISTEN connection.
Sourcepub fn connect(conninfo: &str, max_size: usize) -> Result<Self, StoreError>
pub fn connect(conninfo: &str, max_size: usize) -> Result<Self, StoreError>
Convenience constructor from a libpq conninfo string / URL.
pub fn connect_in_schema( conninfo: &str, max_size: usize, schema: &str, ) -> Result<Self, StoreError>
pub fn connect_with_options( conninfo: &str, max_size: usize, opts: PgStoreOptions, ) -> Result<Self, StoreError>
pub fn connect_in_schema_with_options( conninfo: &str, max_size: usize, opts: PgStoreOptions, schema: &str, ) -> Result<Self, StoreError>
Sourcepub async fn begin(&self) -> Result<PgTx, StoreError>
pub async fn begin(&self) -> Result<PgTx, StoreError>
Begin a store transaction for the Transactional port. The handle owns its
connection; dropping it without commit detaches the connection from the pool so
the open transaction aborts server-side instead of leaking into the next lease
of that connection.
Sourcepub async fn enqueue_on<C: GenericClient>(
&self,
c: &C,
batch: &[Envelope],
) -> Result<(), StoreError>
pub async fn enqueue_on<C: GenericClient>( &self, c: &C, batch: &[Envelope], ) -> Result<(), StoreError>
Enqueue on an explicit transaction — the shared path behind enqueue,
enqueue_tx, and direct tokio_postgres::Transaction interop (caller-owned transaction contract).
Trait Implementations§
Source§impl CheckpointInspect for PgStore
impl CheckpointInspect for PgStore
Source§fn get_job_checkpoint<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Checkpoint>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_job_checkpoint<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Checkpoint>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
None means the job does not exist; an existing job
with no resumable progress returns an empty Checkpoint.Source§impl Inspect for PgStore
impl Inspect for PgStore
Source§fn as_result_inspect(&self) -> Option<&dyn ResultInspect>
fn as_result_inspect(&self) -> Option<&dyn ResultInspect>
Source§fn as_output_inspect(&self) -> Option<&dyn OutputInspect>
fn as_output_inspect(&self) -> Option<&dyn OutputInspect>
Source§fn as_progress_inspect(&self) -> Option<&dyn ProgressInspect>
fn as_progress_inspect(&self) -> Option<&dyn ProgressInspect>
Source§fn as_checkpoint_inspect(&self) -> Option<&dyn CheckpointInspect>
fn as_checkpoint_inspect(&self) -> Option<&dyn CheckpointInspect>
fn get_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
include_payload: bool,
) -> Pin<Box<dyn Future<Output = Result<Option<JobSummary>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_jobs<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
filter: &'life1 JobFilter,
cursor: Option<&'life2 str>,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<JobPage, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn counts<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: Option<&'life1 str>,
) -> Pin<Box<dyn Future<Output = Result<StateCounts, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn queue_stats<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<QueueStats>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn set_queue_paused<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
paused: bool,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn set_queue_weight<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
weight: u32,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_queue_weight<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
weight: u32,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
weight == 0 is invalid; omitted/unconfigured queues read as weight 1.Source§fn set_enqueue_limit<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
max_unfinished_jobs: Option<u64>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_enqueue_limit<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
max_unfinished_jobs: Option<u64>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn rate_classes<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<RateClassState>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn upsert_rate_class<'life0, 'life1, 'async_trait>(
&'life0 self,
cfg: &'life1 RateClassConfig,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn upsert_rate_class<'life0, 'life1, 'async_trait>(
&'life0 self,
cfg: &'life1 RateClassConfig,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn concurrency_limits<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<ConcurrencyLimitConfig>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn upsert_concurrency_limit<'life0, 'life1, 'async_trait>(
&'life0 self,
cfg: &'life1 ConcurrencyLimitConfig,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn partitions<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<PartitionState>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn quarantine_list<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<QuarantineEntry>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn quarantine_release<'life0, 'life1, 'async_trait>(
&'life0 self,
fingerprint: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn quarantine_release<'life0, 'life1, 'async_trait>(
&'life0 self,
fingerprint: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
operator_release) and new enqueues are accepted again. Returns how
many jobs were released. A released job re-quarantines on its next crash.Source§fn operator_retry<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn operator_retry<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
archived → available (operator_retry). Any other state is an error — the
transition table defines exactly which rows exist.Source§fn operator_cancel<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn operator_cancel<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
scheduled|available|running → cancelled (operator_cancel). Cancelling a
running job clears its lease, so the holder’s next renew/ack/checkpoint is
rejected and its handler stops within a heartbeat.Source§fn delete_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn explain_admission<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<AdmissionExplain>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn history<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
since_ms: i64,
bucket_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<HistoryBucket>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn history<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
since_ms: i64,
bucket_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<HistoryBucket>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn quarantine_sweep<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn quarantine_sweep<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
quarantined state, VISIBLY — without this
they sit gate-excluded forever, which is an invisible skip. Returns how many
moved. Bounded per call; run under a duty lease.Source§fn reschedule_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
at_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn reschedule_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
at_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
scheduled and retryable —
no state changes, so no transition-table row is needed.Source§fn edit_payload<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
id: &'life1 str,
payload: &'life2 [u8],
schema_version: u32,
fingerprint: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn edit_payload<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
id: &'life1 str,
payload: &'life2 [u8],
schema_version: u32,
fingerprint: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Source§fn upsert_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
s: &'life1 Schedule,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn upsert_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
s: &'life1 Schedule,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
upsertJobScheduler). next_run_ms is kept from
the existing row when the spec is unchanged, so re-deploying a config does not
reset the phase of a running schedule.fn delete_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_schedules<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<Schedule>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn due_schedules<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Schedule>, i64), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn due_schedules<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Schedule>, i64), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn advance_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
from_next_run_ms: i64,
to_next_run_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn advance_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
from_next_run_ms: i64,
to_next_run_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
next_run_ms still equals from.
Losing the race means another node already advanced — never an error.Source§fn record_schedule_event<'life0, 'life1, 'async_trait>(
&'life0 self,
event: &'life1 ScheduleEvent,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn record_schedule_event<'life0, 'life1, 'async_trait>(
&'life0 self,
event: &'life1 ScheduleEvent,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn list_schedule_events<'life0, 'life1, 'async_trait>(
&'life0 self,
schedule_id: &'life1 str,
before_event_id: Option<u64>,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<Vec<ScheduleEvent>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_schedule_events<'life0, 'life1, 'async_trait>(
&'life0 self,
schedule_id: &'life1 str,
before_event_id: Option<u64>,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<Vec<ScheduleEvent>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
limit must be in 1..=SCHEDULE_EVENT_LIMIT.Source§fn heartbeat_worker<'life0, 'life1, 'async_trait>(
&'life0 self,
w: &'life1 WorkerMeta,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn heartbeat_worker<'life0, 'life1, 'async_trait>(
&'life0 self,
w: &'life1 WorkerMeta,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn signal_worker<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
worker_id: &'life1 str,
command: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn signal_worker<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
worker_id: &'life1 str,
command: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
None) a worker’s pending command. It is delivered on the
next heartbeat; runtimes clear it after applying it, then publish acknowledged state.Source§fn distinct_kinds<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn distinct_kinds<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn list_workers<'life0, 'async_trait>(
&'life0 self,
stale_after_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkerMeta>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn list_workers<'life0, 'async_trait>(
&'life0 self,
stale_after_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkerMeta>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
stale_after_ms of store-now.fn create_operation<'life0, 'life1, 'async_trait>(
&'life0 self,
req: &'life1 BulkRequest,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_operation<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<OperationStatus>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn run_pending_operations<'life0, 'async_trait>(
&'life0 self,
batch: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn run_pending_operations<'life0, 'async_trait>(
&'life0 self,
batch: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn promote_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn promote_job<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
pending -> available. No timer or dependency watcher may perform this change.Source§fn delete_queue<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
force: bool,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete_queue<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 str,
force: bool,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
force; forced deletion is represented by a
bounded async operation and therefore returns its operation id.Source§fn sample_queue_memory<'life0, 'async_trait>(
&'life0 self,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<u32, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn sample_queue_memory<'life0, 'async_trait>(
&'life0 self,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<u32, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
limit;
ordinary queue reads only return the last stored sample.Source§impl Notifying for PgStore
impl Notifying for PgStore
Source§fn wait_wakeup<'life0, 'life1, 'async_trait>(
&'life0 self,
queues: &'life1 [String],
timeout: Duration,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn wait_wakeup<'life0, 'life1, 'async_trait>(
&'life0 self,
queues: &'life1 [String],
timeout: Duration,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
timeout for a hint that work may be available. An empty queues
slice matches ANY queue (the UI’s one-subscription case, bounded live-control contract). Returns the
waking queue’s name, or None on timeout. Wakeups may be spurious; callers
admit either way when their poll timer expires — a wakeup only shortcuts it.Source§impl OutputInspect for PgStore
impl OutputInspect for PgStore
Source§fn get_job_output<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<JobOutput>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_job_output<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<JobOutput>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
JobOutput::fence identifies its author.Source§impl OutputStore for PgStore
impl OutputStore for PgStore
fn write_job_output<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
output: &'life2 JobResult,
) -> Pin<Box<dyn Future<Output = Result<JobOutput, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§impl ProgressInspect for PgStore
impl ProgressInspect for PgStore
Source§fn get_job_progress<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<JobProgress>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_job_progress<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<JobProgress>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
JobProgress::fence makes that provenance explicit.Source§impl ProgressStore for PgStore
impl ProgressStore for PgStore
fn write_job_progress<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
update: &'life2 ProgressUpdate,
) -> Pin<Box<dyn Future<Output = Result<JobProgress, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§impl ResultInspect for PgStore
impl ResultInspect for PgStore
Source§fn get_job_result<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<JobResult>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_job_result<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<JobResult>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
None for a missing job or a job
with no completed result; payload/list reads never include these bytes implicitly.Source§impl ResultStore for PgStore
impl ResultStore for PgStore
fn ack_success_with_result<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
logs: &'life2 [String],
actual_weight: Option<u32>,
result: &'life3 JobResult,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Source§impl Store for PgStore
impl Store for PgStore
Source§fn admit<'life0, 'async_trait>(
&'life0 self,
req: AdmitRequest,
) -> Pin<Box<dyn Future<Output = Result<Vec<AdmissionUnit>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn admit<'life0, 'async_trait>(
&'life0 self,
req: AdmitRequest,
) -> Pin<Box<dyn Future<Output = Result<Vec<AdmissionUnit>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn ack_attempt_with_actual_weight<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
outcome: Outcome,
err: Option<&'life2 str>,
delay_ms: Option<i64>,
logs: &'life3 [String],
actual_weight: Option<u32>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn ack_attempt_with_actual_weight<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
outcome: Outcome,
err: Option<&'life2 str>,
delay_ms: Option<i64>,
logs: &'life3 [String],
actual_weight: Option<u32>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Store::ack_attempt plus surveyed policy behavior cost reconciliation. Admission charges the
envelope’s estimated weight; Some(actual) corrects that charge under the
same fence and in the same atomic write as the state transition. Some(0) is a
real full refund; None means the estimate was exact. The extra method is kept
coarse on purpose: a separate reconcile call could commit after a rejected ack.Source§fn renew<'life0, 'life1, 'async_trait>(
&'life0 self,
leases: &'life1 [LeaseRef],
lease: Duration,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn renew<'life0, 'life1, 'async_trait>(
&'life0 self,
leases: &'life1 [LeaseRef],
lease: Duration,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn enqueue<'life0, 'life1, 'async_trait>(
&'life0 self,
batch: &'life1 [Envelope],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn checkpoint<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
cp: &'life2 Checkpoint,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn checkpoint<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
cp: &'life2 Checkpoint,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
LeaseRejected here means STOP — do not run the next step’s side effects.
Durable BEFORE the step runs, never after the worker returns (River’s mistake).Source§fn reclaim_expired<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<Reclaimed>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn reclaim_expired<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<Vec<Reclaimed>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Outcome::LeaseLost,
NEVER Retry: it increments crash_attempt and leaves attempt alone. At the
crash limit the job parks in quarantined and its fingerprint is registered.
Safe under contention; run it via a duty lease to avoid redundant sweeps.Source§fn promote_due<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn promote_due<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
schedule_due/backoff_due sweep: due scheduled and retryable jobs
become available. Returns how many were promoted.Source§fn evict_retained<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn evict_retained<'life0, 'async_trait>(
&'life0 self,
limit: i64,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
finalized_at_ms + retention_ms
has lapsed are deleted (the transition table’s completed -> deleted by
retention; retention_ms = 0 already deleted at ack time). quarantined is
exempt — it parks VISIBLY until an operator acts, never silently expires.
Bounded per call; run under the retention duty lease.Source§fn claim_duty<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
name: &'life1 str,
holder: &'life2 str,
lease: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn claim_duty<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
name: &'life1 str,
holder: &'life2 str,
lease: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
false = someone else
holds it; skip this tick, never block on it.Source§fn release_duty<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
name: &'life1 str,
holder: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn release_duty<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
name: &'life1 str,
holder: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn caps(&self) -> Caps
Source§fn as_transactional(&self) -> Option<&dyn Transactional>
fn as_transactional(&self) -> Option<&dyn Transactional>
None means genuinely unsupported — never a
silent no-op, and never a config knob that does nothing.Source§fn as_result_store(&self) -> Option<&dyn ResultStore>
fn as_result_store(&self) -> Option<&dyn ResultStore>
ResultStore returns it here.Source§fn as_output_store(&self) -> Option<&dyn OutputStore>
fn as_output_store(&self) -> Option<&dyn OutputStore>
Source§fn as_progress_store(&self) -> Option<&dyn ProgressStore>
fn as_progress_store(&self) -> Option<&dyn ProgressStore>
Source§fn as_inspect(&self) -> Option<&dyn Inspect>
fn as_inspect(&self) -> Option<&dyn Inspect>
as_transactional.Source§fn as_notifying(&self) -> Option<&dyn Notifying>
fn as_notifying(&self) -> Option<&dyn Notifying>
Source§fn ack<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
outcome: Outcome,
err: Option<&'life2 str>,
delay_ms: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn ack<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
outcome: Outcome,
err: Option<&'life2 str>,
delay_ms: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
outcome, write the error history, honour the
fence. delay_ms: required for Snooze (must be > 0); for Retry it overrides
the store’s default backoff (the retry-policy port computes it caller-side);
ignored otherwise. LeaseLost is never acked — it is the reclaimer’s transition.
Convenience over Store::ack_attempt with no logs.Source§fn ack_attempt<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
outcome: Outcome,
err: Option<&'life2 str>,
delay_ms: Option<i64>,
logs: &'life3 [String],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn ack_attempt<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
lease: &'life1 LeaseRef,
outcome: Outcome,
err: Option<&'life2 str>,
delay_ms: Option<i64>,
logs: &'life3 [String],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
Store::ack plus attempt-log contract per-attempt execution logs (River’s riverlog):
captured handler log lines land INSIDE the attempt’s error-history entry, so
the console shows why an attempt failed, not just that it did. Recorded for
success / retry / skip / undecodable (a non-empty logs on success writes a
success entry — the only time one exists); dropped for snooze / rate_limited /
revoke, which by design record no attempt entry.Source§impl Transactional for PgStore
impl Transactional for PgStore
Source§fn begin_tx<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn TxHandle>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn begin_tx<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn TxHandle>, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
dyn Transactional, like [Job.Once]-style helpers.fn commit_tx<'life0, 'async_trait>(
&'life0 self,
tx: Box<dyn TxHandle>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn rollback_tx<'life0, 'async_trait>(
&'life0 self,
tx: Box<dyn TxHandle>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn claim_effect<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
key: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn claim_effect<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
key: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
false means the key
was already claimed by a COMMITTED transaction — the effect ran; skip the work.
The claim commits (or vanishes) with everything else in the transaction, which
is the entire mechanism behind at-most-once effects.Source§fn checkpoint_tx<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
lease: &'life2 LeaseRef,
cp: &'life3 Checkpoint,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn checkpoint_tx<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
lease: &'life2 LeaseRef,
cp: &'life3 Checkpoint,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
once claims {job}/{step}, does its writes, and records the step
complete — atomically. A superseded holder fails here and everything rolls back.fn enqueue_tx<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
batch: &'life2 [Envelope],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn complete_tx_with_actual_weight<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
lease: &'life2 LeaseRef,
actual_weight: Option<u32>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn complete_tx_with_actual_weight<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tx: &'life1 mut dyn TxHandle,
lease: &'life2 LeaseRef,
actual_weight: Option<u32>,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
once completes inside the caller’s transaction;
reconciling outside it could charge an effect whose fenced completion rolled back.