Application-owned persistence contract for the Tasks extension.
A request context crosses this boundary only through authorize/3. The
resulting access value is opaque and deliberately scoped to one action. All
mutations after that point are explicit, JSON-safe events guarded by an
expected snapshot revision.
Creation atomically persists the initial Task and its serializable work
descriptor. Runners then acquire renewable, opaque claims. A lease can
authorize only worker lifecycle events for its exact task and claim
generation; it is not a substitute for fresh request authorization on
tasks/get, tasks/update, or tasks/cancel.
claim_next/3 is the recovery seam. Expired or adapter-invalidated claims may
be reacquired at a higher generation, fencing the previous worker. Both exact
and recovery claims must also enforce the snapshot's persisted retry_at
against store-authoritative time. Reaping removes the entire aggregate using
the Task's creation-based TTL.
Store references use {module, state} so implementations may be processes,
database repositories, external job systems, or immutable test doubles.
Summary
Functions
Acquires opaque, action-bound request access without retaining the context.
Atomically claims one exact nonterminal task whose retry delay is due.
Atomically claims the next available, retry-due recoverable task.
Deletes complete task aggregates whose creation-based TTL has elapsed.
Releases a matching claim so another runner may recover it immediately.
Extends a live worker claim without changing task state or revision.
Reads the current aggregate through an exact, live worker lease.
Types
@type access() :: term()
@type authority() :: {:request, access()} | {:worker, worker_lease()}
@type claim_next_result() :: {:ok, Snodo.Extensions.Tasks.Snapshot.t(), worker_lease()} | :empty | {:error, term()}
@type claim_result() :: {:ok, Snodo.Extensions.Tasks.Snapshot.t(), worker_lease()} | {:deferred, pos_integer()} | :unavailable | :not_found | {:error, term()}
@type lookup_result() :: {:ok, Snodo.Extensions.Tasks.Snapshot.t()} | :not_found | {:error, term()}
@type transition_result() :: {:ok, Snodo.Extensions.Tasks.Transition.t()} | {:conflict, Snodo.Extensions.Tasks.Snapshot.t()} | :not_found | {:error, term()}
@type worker_lease() :: term()
Callbacks
@callback authorize(store :: term(), Snodo.Context.t(), action()) :: {:ok, access()} | {:error, term()}
@callback claim( store :: term(), task_id :: String.t(), owner_id :: String.t(), lease_ms :: pos_integer() ) :: claim_result()
@callback claim_next(store :: term(), owner_id :: String.t(), lease_ms :: pos_integer()) :: claim_next_result()
@callback create( store :: term(), Snodo.Extensions.Tasks.Task.t(), Snodo.Extensions.Tasks.Work.t(), access() ) :: {:ok, Snodo.Extensions.Tasks.Snapshot.t()} | {:error, term()}
@callback get(store :: term(), task_id :: String.t(), access()) :: lookup_result()
@callback release(store :: term(), worker_lease()) :: :ok | {:error, term()}
@callback renew(store :: term(), worker_lease(), lease_ms :: pos_integer()) :: {:ok, worker_lease()} | {:error, term()}
@callback transition( store :: term(), task_id :: String.t(), expected_revision :: non_neg_integer(), Snodo.Extensions.Tasks.Event.t(), authority() ) :: transition_result()
@callback worker_snapshot(store :: term(), task_id :: String.t(), worker_lease()) :: lookup_result()
Functions
@spec authorize(ref(), Snodo.Context.t(), action()) :: {:ok, access()} | {:error, term()}
Acquires opaque, action-bound request access without retaining the context.
@spec claim(ref(), String.t(), String.t(), pos_integer()) :: claim_result()
Atomically claims one exact nonterminal task whose retry delay is due.
@spec claim_next(ref(), String.t(), pos_integer()) :: claim_next_result()
Atomically claims the next available, retry-due recoverable task.
@spec create( ref(), Snodo.Extensions.Tasks.Task.t(), Snodo.Extensions.Tasks.Work.t(), access() ) :: {:ok, Snodo.Extensions.Tasks.Snapshot.t()} | {:error, term()}
@spec get(ref(), String.t(), access()) :: lookup_result()
Deletes complete task aggregates whose creation-based TTL has elapsed.
@spec release(ref(), worker_lease()) :: :ok | {:error, term()}
Releases a matching claim so another runner may recover it immediately.
@spec renew(ref(), worker_lease(), pos_integer()) :: {:ok, worker_lease()} | {:error, term()}
Extends a live worker claim without changing task state or revision.
@spec transition( ref(), String.t(), non_neg_integer(), Snodo.Extensions.Tasks.Event.t(), authority() ) :: transition_result()
@spec worker_snapshot(ref(), String.t(), worker_lease()) :: lookup_result()
Reads the current aggregate through an exact, live worker lease.