pub struct PostgresProvider { /* private fields */ }postgres only.Expand description
Postgres-backed StateProvider, built on sqlx and the canonical DBOS
schema (workflow_status / operation_outputs).
Implementations§
Source§impl PostgresProvider
impl PostgresProvider
Sourcepub async fn connect(database_url: &str) -> Result<Self>
pub async fn connect(database_url: &str) -> Result<Self>
Connect to Postgres using a standard connection URL, e.g.
postgres://user:pass@localhost:5432/durare.
System tables live in the dbos schema — the same one every DBOS SDK
defaults to, so a database shared with Go/Python workers just works. Use
connect_with_schema to isolate a tenant
under a different schema.
Sourcepub async fn connect_with_schema(
database_url: &str,
schema: &str,
) -> Result<Self>
pub async fn connect_with_schema( database_url: &str, schema: &str, ) -> Result<Self>
Like connect but with an explicit system-tables
schema — e.g. one schema per tenant sharing a database. The schema is
created if missing and migrated independently on init (each schema has
its own migration history). The name must be a plain identifier
([A-Za-z_][A-Za-z0-9_]*).
Implementation: every pooled connection starts with search_path set to
the schema, so all queries — including a transactional step’s user SQL —
resolve inside it. One caveat: LISTEN/NOTIFY channel names are shared
database-wide, so tenants in one database may wake each other spuriously;
wakeups are only hints (the state is always re-read), so this affects
latency noise, not correctness.
Sourcepub fn from_pool(pool: PgPool) -> Self
pub fn from_pool(pool: PgPool) -> Self
Build a provider from an existing pool (useful if your app already owns
one). The pool’s own configuration controls the search path, so system
tables live wherever it resolves unqualified names (no schema is created
on init).
Sourcepub fn pool(&self) -> &PgPool
pub fn pool(&self) -> &PgPool
The underlying connection pool (e.g. for application queries that should share the provider’s connections and search path).
Sourcepub fn with_serializer(self, serializer: Serializer) -> Self
pub fn with_serializer(self, serializer: Serializer) -> Self
Choose the format new values are encoded with. Use Serializer::Portable
when this database is shared with DBOS workers in other languages.
Trait Implementations§
Source§impl Drop for PostgresProvider
impl Drop for PostgresProvider
Source§impl StateProvider for PostgresProvider
impl StateProvider for PostgresProvider
Source§fn init<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn init<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn supports_listen_notify(&self) -> bool
fn supports_listen_notify(&self) -> bool
LISTEN/NOTIFY),
so a blocked recv/get_event is woken as soon as the row it waits for
is written rather than only by polling. Callers that get true can wait
on a long backstop interval and rely on await_change
for promptness; false means they must poll at a short interval.Source§fn serializer(&self) -> Serializer
fn serializer(&self) -> Serializer
set_workflow_status &str channel cannot —
so a portable provider writes the cross-language error envelope. Defaults
to Serializer::Json (bare error strings); the SQL providers return
their configured serializer.Source§fn await_change<'life0, 'life1, 'async_trait>(
&'life0 self,
wait: ChangeWait<'life1>,
within: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn await_change<'life0, 'life1, 'async_trait>(
&'life0 self,
wait: ChangeWait<'life1>,
within: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
within for a hint that wait’s condition may have changed,
returning early when a matching change is signalled. The wake is only a
hint: the caller must re-check the database (a signal can be missed in the
gap between the caller’s last check and subscribing — the bounded within
is the backstop). Backends without push signalling just sleep.Source§fn insert_workflow_status<'life0, 'async_trait>(
&'life0 self,
s: WorkflowStatus,
) -> Pin<Box<dyn Future<Output = Result<(WorkflowStatus, bool)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn insert_workflow_status<'life0, 'async_trait>(
&'life0 self,
s: WorkflowStatus,
) -> Pin<Box<dyn Future<Output = Result<(WorkflowStatus, bool)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
status.id already exists, the
existing row is returned unchanged (so a re-submitted id is a no-op, not a
duplicate). This is the single creation path for both direct runs and
enqueues. Read moreSource§fn get_deduplicated_workflow<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
queue_name: &'life1 str,
dedup_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn get_deduplicated_workflow<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
queue_name: &'life1 str,
dedup_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
(queue_name, dedup_id), if any. Backs
DeduplicationPolicy::ReturnExisting:
on a dedup collision the enqueue returns a handle to this workflow.Source§fn get_workflow_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<WorkflowStatus>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_workflow_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<WorkflowStatus>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn set_workflow_status<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
id: &'life1 str,
status: &'life2 str,
output: Option<&'life3 Value>,
error: Option<&'life4 str>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn set_workflow_status<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
id: &'life1 str,
status: &'life2 str,
output: Option<&'life3 Value>,
error: Option<&'life4 str>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
output or error. Bumps updated_at.Source§fn get_step_result<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<RecordedStep>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_step_result<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<RecordedStep>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
None if the step has not run. The
name lets the replayer detect a non-deterministic workflow (a different
operation recorded at this position than the one now executing).Source§fn record_step_result<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
name: &'life2 str,
value: Value,
error: Option<&'life3 str>,
started_at_ms: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<StepOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn record_step_result<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
name: &'life2 str,
value: Value,
error: Option<&'life3 str>,
started_at_ms: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<StepOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
(workflow_id, seq): its
success value, or — when error is set — its already-encoded failure
(stored in the error column, output left null). A step records exactly
one of the two. Read moreSource§fn run_transaction_step<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
started_at_ms: i64,
opts: &'life2 TransactionOptions,
body: TxBody<'life3>,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn run_transaction_step<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
started_at_ms: i64,
opts: &'life2 TransactionOptions,
body: TxBody<'life3>,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
body’s SQL writes and this step’s
operation_outputs checkpoint commit in one database transaction, so
the writes happen exactly once. Returns the step’s recorded outcome — its
output as Ok (body’s on the first run, the stored one on replay), or a
recorded failure as Err. Read moreSource§fn dequeue_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
req: &'life1 DequeueRequest,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowStatus>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn dequeue_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
req: &'life1 DequeueRequest,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowStatus>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
req.max_tasks ENQUEUED workflows from a queue,
transitioning them to PENDING stamped with the claiming executor, the
app version, and started_at. Candidates are ordered by
(priority, created_at). Honors global_concurrency (queue-wide PENDING
cap) and the rate-limit window if set; for workflows with a stored
timeout_ms, the absolute deadline is fixed at claim time. Read moreSource§fn transition_delayed_workflows<'life0, 'async_trait>(
&'life0 self,
now_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn transition_delayed_workflows<'life0, 'async_trait>(
&'life0 self,
now_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
DELAYED workflow whose delay_until_ms <= now_ms to
ENQUEUED. Returns how many were transitioned. Called by the dispatcher
at the top of each polling iteration.Source§fn queue_partitions<'life0, 'life1, 'async_trait>(
&'life0 self,
queue_name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn queue_partitions<'life0, 'life1, 'async_trait>(
&'life0 self,
queue_name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
ENQUEUED workflows on
queue_name. The dispatcher of a partitioned queue iterates these and
dequeues each partition independently.Source§fn insert_notification<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
destination_id: &'life1 str,
topic: &'life2 str,
message: Value,
idempotency_key: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn insert_notification<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
destination_id: &'life1 str,
topic: &'life2 str,
message: Value,
idempotency_key: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
destination_id on topic. Errors if the
destination workflow does not exist (FK violation in the SQL backends). Read moreSource§fn consume_notification<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
topic: &'life2 str,
seq: i32,
step_name: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn consume_notification<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
topic: &'life2 str,
seq: i32,
step_name: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
(workflow_id, topic) and record it as the step checkpoint
(workflow_id, seq) in the same transaction — if claiming and
checkpointing were separate, a crash between them would lose the
message. Returns the message, or None when the mailbox is empty
(nothing is recorded in that case).Source§fn upsert_event<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
value: Value,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn upsert_event<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
value: Value,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
key on workflow_id.Source§fn get_event_value<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn get_event_value<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
key on workflow_id, if set.Source§fn list_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 ListFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowStatus>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 ListFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowStatus>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
filter, newest- or oldest-first per
filter.sort_desc.Source§fn get_workflow_aggregates<'life0, 'life1, 'async_trait>(
&'life0 self,
query: &'life1 WorkflowAggregateQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowAggregate>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_workflow_aggregates<'life0, 'life1, 'async_trait>(
&'life0 self,
query: &'life1 WorkflowAggregateQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowAggregate>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
query (one WorkflowAggregate per
non-empty group). The engine validates that the query groups by at least
one dimension before calling this.Source§fn get_step_aggregates<'life0, 'life1, 'async_trait>(
&'life0 self,
query: &'life1 StepAggregateQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<StepAggregate>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_step_aggregates<'life0, 'life1, 'async_trait>(
&'life0 self,
query: &'life1 StepAggregateQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<StepAggregate>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
operation_outputs) rows grouped per query, selecting
count and/or max duration. The engine validates that the query groups by
at least one dimension and selects at least one aggregate before calling.Source§fn cancel_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn cancel_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
CANCELLED,
stamp completed_at, and clear queue assignment / dedup so it leaves any
queue. A running workflow stops cooperatively at its next step.Source§fn resume_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn resume_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
CANCELLED (or otherwise non-terminal) workflow by returning it
to PENDING, resetting recovery_attempts and clearing deadline / dedup
/ started / completed. Returns true if a row was actually transitioned
(i.e. it existed and was not already SUCCESS/ERROR). The caller
re-dispatches it.Source§fn enqueue_existing<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 str,
queue: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn enqueue_existing<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 str,
queue: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
ENQUEUED on queue, clearing
the owning executor and start time so a dispatcher claims it fresh. Used
to re-execute a resumed workflow on a running engine without
re-running it locally. A no-op if the id is gone.Source§fn cancel_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn cancel_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
CANCELLED (same effect as cancel_workflow);
missing or already-terminal ids are silently skipped (no error). An empty
slice is a no-op.Source§fn resume_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn resume_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
SUCCESS/ERROR returns to PENDING (same effect as
resume_workflow). Returns the ids actually
transitioned, so the caller can re-dispatch exactly those. An empty slice
returns an empty vec.Source§fn delete_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [String],
delete_children: bool,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete_workflows<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [String],
delete_children: bool,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
ON DELETE CASCADE) their step / event / stream
rows, regardless of state. When delete_children, every descendant by
parent_workflow_id (transitively) is deleted too. Missing ids are
skipped. An empty slice is a no-op.Source§fn set_workflow_delay<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
delay_until_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_workflow_delay<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
delay_until_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
DELAYED workflow: set its delay_until to
delay_until_ms. Only affects a row currently in DELAYED (a queue
dispatcher promotes it to ENQUEUED once due); anything else is a no-op.
Returns whether a row was updated.Source§fn fork_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
params: &'life1 ForkParams,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn fork_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
params: &'life1 ForkParams,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
params.new_id as a fork of params.original_id: a fresh
ENQUEUED workflow on params.queue_name with the same
name/input/auth/class/config/app-id, forked_from = original_id, and the
original’s step checkpoints with seq < start_step copied in so
execution resumes from that step. Marks the original was_forked_from.
Errors if the original does not exist.Source§fn bump_recovery_attempts<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
max: i32,
) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn bump_recovery_attempts<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
max: i32,
) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
recovery_attempts and return the new
value. If it exceeds max, the workflow is parked in
MAX_RECOVERY_ATTEMPTS_EXCEEDED instead of being recovered again.Source§fn record_child_workflow<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
parent_id: &'life1 str,
seq: i32,
name: &'life2 str,
child_id: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn record_child_workflow<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
parent_id: &'life1 str,
seq: i32,
name: &'life2 str,
child_id: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
parent_id’s step seq started child workflow
child_id. Stored as an operation_outputs checkpoint carrying the child
id, so a replay of the parent re-attaches to the same child instead of
starting a new one. A second record for the same (parent_id, seq) is a
no-op.Source§fn check_child_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
parent_id: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<(String, String)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn check_child_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
parent_id: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<(String, String)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
(child_id, recorded_name) for the child workflow parent_id
started at step seq, if one was recorded by
record_child_workflow. The recorded
name lets the replayer detect a non-deterministic parent (a different
child recorded at this position than the one now being started).Source§fn get_workflow_steps<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<StepInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_workflow_steps<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<StepInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
operation_outputs rows) as
StepInfo, ordered by step_id. Outputs are decoded per each row’s
recorded serialization format. Returns an empty list for an unknown
workflow or one that has run no steps.Source§fn get_step_name<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_step_name<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
function_name recorded at (workflow_id, seq), if a row exists.
Used by the patch system to tell a marker from a pre-patch step.Source§fn record_patch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
name: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn record_patch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
seq: i32,
name: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
(workflow_id, seq) (no
output) — the checkpoint the patch system writes so a replay observes the
same patch decision. A second record for the same key is a no-op.Source§fn write_stream<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
value: Option<Value>,
function_id: i32,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn write_stream<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
value: Option<Value>,
function_id: i32,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
(workflow_id, key) at the
next offset (MAX(offset) + 1, starting at 0), stamped with the producing
step’s function_id. value is the user value to encode and store;
None writes the close sentinel instead, which seals the stream. Errors
if the stream is already closed. The destination workflow’s existence is
enforced by the streams foreign key.Source§fn read_stream<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
from_offset: i32,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Value>, bool)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn read_stream<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
key: &'life2 str,
from_offset: i32,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Value>, bool)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
(workflow_id, key) entries with offset >= from_offset in
order, decoding each per its stored serialization. Returns the decoded
values and whether the close sentinel was reached (the sentinel itself is
not included). Reading never blocks — the caller polls.Source§fn list_workflow_events<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<(String, Value)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_workflow_events<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<(String, Value)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
(key, value) events set on a workflow (set_event), decoded per
their stored serialization, ordered by key. For observability/control
planes that surface a workflow’s events.Source§fn list_workflow_notifications<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<NotificationInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_workflow_notifications<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<NotificationInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
send/recv mailbox), oldest
first, with each message decoded. Includes already-consumed entries.Source§fn list_workflow_streams<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<(String, Vec<Value>)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_workflow_streams<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<(String, Vec<Value>)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn create_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
schedule: &'life1 WorkflowSchedule,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn create_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
schedule: &'life1 WorkflowSchedule,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
schedule_name is unique, so creating one that
already exists is a unique violation.Source§fn apply_schedules<'life0, 'life1, 'async_trait>(
&'life0 self,
schedules: &'life1 [WorkflowSchedule],
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn apply_schedules<'life0, 'life1, 'async_trait>(
&'life0 self,
schedules: &'life1 [WorkflowSchedule],
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
schedule_id for each beforehand.Source§fn list_schedules<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 ScheduleFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowSchedule>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_schedules<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 ScheduleFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowSchedule>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
filter (empty filter returns every schedule),
ordered by schedule_name.Source§fn set_schedule_status<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
status: ScheduleStatus,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_schedule_status<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
status: ScheduleStatus,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn set_schedule_last_fired<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
at_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_schedule_last_fired<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
at_ms: i64,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
last_fired_at (epoch ms) on a schedule. A no-op if it is gone.Source§fn delete_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete_schedule<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn create_application_version<'life0, 'life1, 'async_trait>(
&'life0 self,
version_name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn create_application_version<'life0, 'life1, 'async_trait>(
&'life0 self,
version_name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
version_name
already exists). Stamps both timestamps with now.Source§fn list_application_versions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<VersionInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn list_application_versions<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<VersionInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
version_timestamp first.Source§fn get_latest_application_version<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Option<VersionInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_latest_application_version<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Option<VersionInfo>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
version_timestamp, or None if none
are registered.Source§fn set_latest_application_version<'life0, 'life1, 'async_trait>(
&'life0 self,
version_name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_latest_application_version<'life0, 'life1, 'async_trait>(
&'life0 self,
version_name: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
version_timestamp to now.
Returns whether a row matched (no-op if the name is unknown).Source§fn upsert_queue<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 WorkflowQueue,
update_existing: bool,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn upsert_queue<'life0, 'life1, 'async_trait>(
&'life0 self,
queue: &'life1 WorkflowQueue,
update_existing: bool,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
queues table — the
database-backed registry the conductor reads fleet-wide, distinct from the
engine’s in-process registry. Keyed by name: a first write inserts;
a name collision does nothing unless update_existing, which overwrites
the stored configuration. Called once per registered queue on launch.Source§fn list_queues<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowQueue>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn list_queues<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<WorkflowQueue>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
queues table, sorted by name — the
database-backed (fleet-wide) counterpart to the engine’s in-process
list_registered_queues. Fields not stored in the table
(max_tasks_per_iteration, max_polling_interval) come back at their
defaults.Source§fn export_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
export_children: bool,
) -> Pin<Box<dyn Future<Output = Result<Vec<ExportedWorkflow>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn export_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
workflow_id: &'life1 str,
export_children: bool,
) -> Pin<Box<dyn Future<Output = Result<Vec<ExportedWorkflow>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
export_children) all of its transitive
children into the portable ExportedWorkflow form. The root workflow is
first in the returned list, followed by descendants discovered through
parent_workflow_id. Errors if the root workflow does not exist.Source§fn import_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
workflows: &'life1 [ExportedWorkflow],
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn import_workflow<'life0, 'life1, 'async_trait>(
&'life0 self,
workflows: &'life1 [ExportedWorkflow],
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
export_workflowed workflows,
re-inserting each one’s workflow_status row and dependent rows. Atomic:
either every workflow is imported or none is. A workflow whose id already
exists is an error (import does not overwrite).Auto Trait Implementations§
impl !Freeze for PostgresProvider
impl !RefUnwindSafe for PostgresProvider
impl !UnwindSafe for PostgresProvider
impl Send for PostgresProvider
impl Sync for PostgresProvider
impl Unpin for PostgresProvider
impl UnsafeUnpin for PostgresProvider
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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