pub struct PostgresStorage<Args> { /* private fields */ }Expand description
A backend for persisting and consuming jobs behind a postgres database
§Features
| Feature | Status | Description |
|---|---|---|
Backend | ✅ | Supports storage and retrieval of tasks |
TaskSink | ✅ | Ability to push new tasks |
Serialization | ✅ | Serialization support for arguments |
Workflow | ✅ | Flexible enough to support workflows |
Web Interface | ✅ | Expose a web interface for monitoring tasks |
FetchById | ✅ | Allow fetching a task by its ID |
RegisterWorker | ✅ | Allow registering a worker with the backend |
MakeShared | ✅ | Share one connection across multiple workers via PostgresStorageFactory |
WaitForCompletion | ✅ | Wait for tasks to complete without blocking |
ResumeById | ✅ | Resume a task by its ID |
ResumeAbandoned | ✅ | Resume abandoned tasks |
ListWorkers | ✅ | List all workers registered with the backend |
ListTasks | ✅ | List all tasks in the backend |
Key: ✅ : Supported | ⚠️ : Not implemented | ❌ : Not Supported | ❗ Limited support
Tests:
§Backend
#[tokio::main]
async fn main() {
// let mut backend = /* snip */;
async fn task(task: u32, worker: WorkerContext) {
// Do some work
}
let worker = WorkerBuilder::new("backend-test")
.backend(backend)
.build(task);
let _ = worker.stream().take(1).collect::<Vec<_>>().await;
}
§TaskSink
#[tokio::main]
async fn main() {
// let mut backend = /* snip */;
backend.push(42).await.unwrap();
async fn task(task: u32, worker: WorkerContext) {
worker.stop().unwrap();
}
let worker = WorkerBuilder::new("task-sink-test")
.backend(backend)
.build(task);
worker.run().await.unwrap();
}
§Serialization
#[tokio::main]
async fn main() {
// let mut backend = /* snip */;
fn assert_codec<B: BackendConfig + WireFormatBackend>(backend: B)
where
B::Codec: Codec<B::Args, Compact=Vec<u8>>,
{
}
assert_codec(backend);
}
§Workflow
#[tokio::main]
async fn main() {
// let mut backend = /* snip */;
backend.push(42).await.unwrap();
async fn task1(task: u32, worker: WorkerContext) -> u32 {
task + 99
}
async fn task2(task: u32, worker: WorkerContext) -> u32 {
task + 1
}
async fn task3(task: u32, worker: WorkerContext) {
assert_eq!(task, 142);
worker.stop().unwrap();
}
let workflow = SteppedFlow::new("test-workflow")
.and_then(task1)
.and_then(task2)
.and_then(task3);
let worker = WorkerBuilder::new("workflow-test")
.backend(backend)
.build(workflow);
worker.run().await.unwrap();
}
§WebUI
#[tokio::main]
async fn main() {
// let mut backend = /* snip */;
fn assert_web_ui<B: Expose<u32, Durable>>(backend: B) {};
assert_web_ui(backend);
}
§WaitForCompletion
#[tokio::main]
async fn main() {
// let mut backend = /* snip */;
fn assert_wait_for_completion<B: WaitForCompletion<u32> + Backend>(backend: B) {};
assert_wait_for_completion(backend);
}
Implementations§
Source§impl PostgresStorage<()>
impl PostgresStorage<()>
Sourcepub async fn setup(pool: &PgPool) -> Result<(), Error>
pub async fn setup(pool: &PgPool) -> Result<(), Error>
Runs the PostgreSQL storage migrations.
§Fresh databases
No manual setup is required. Calling setup() will create the required
tables and migration history.
§Upgrading to 1.0
⚠️ Important: Existing databases created by a pre-
1.0version require a one-time manual migration before callingsetup().
The 1.0 migration history is no longer relocated automatically by
setup(). Follow the “Upgrading to 1.0” section in the README to
perform the required transition.
After the transition has been completed, setup() can be used normally
for subsequent migrations.
§Example
use apalis_postgres::PostgresStorage;
use sqlx::PgPool;
PostgresStorage::<()>::setup(&pool).await?;§Errors
Returns an error if the migrations cannot be applied to the database.
Sourcepub fn migrations() -> Migrator
pub fn migrations() -> Migrator
Get postgres migrations without running them
Source§impl<Args> PostgresStorage<Args>
impl<Args> PostgresStorage<Args>
Sourcepub fn with_pubsub(self) -> PollWith<Self, StreamStrategy<Pubsub>>
pub fn with_pubsub(self) -> PollWith<Self, StreamStrategy<Pubsub>>
Mount a standalone Pubsub which uses its own connection under the hood
Sourcepub fn with_config(self, config: Config) -> Self
pub fn with_config(self, config: Config) -> Self
Configure a new PostgresStorage instance.
Trait Implementations§
Source§impl<Args> Backend for PostgresStorage<Args>
impl<Args> Backend for PostgresStorage<Args>
Source§fn poll_ready(
&mut self,
cx: &mut Context<'_>,
worker: &WorkerContext,
) -> Poll<Result<(), Self::Error>>
fn poll_ready( &mut self, cx: &mut Context<'_>, worker: &WorkerContext, ) -> Poll<Result<(), Self::Error>>
Source§fn poll_next(
&mut self,
cx: &mut Context<'_>,
worker: &WorkerContext,
) -> Poll<Option<Result<PgTask, Self::Error>>>
fn poll_next( &mut self, cx: &mut Context<'_>, worker: &WorkerContext, ) -> Poll<Option<Result<PgTask, Self::Error>>>
Source§fn poll_close(
&mut self,
cx: &mut Context<'_>,
worker: &WorkerContext,
) -> Poll<Result<(), Self::Error>>
fn poll_close( &mut self, cx: &mut Context<'_>, worker: &WorkerContext, ) -> Poll<Result<(), Self::Error>>
Source§impl<Args> BackendConfig for PostgresStorage<Args>
impl<Args> BackendConfig for PostgresStorage<Args>
Source§type Layer = TaskPersistLayer<JsonCodec<Value>, Value>
type Layer = TaskPersistLayer<JsonCodec<Value>, Value>
Source§fn middleware(&mut self, _: &mut WorkerContext) -> Self::Layer
fn middleware(&mut self, _: &mut WorkerContext) -> Self::Layer
Source§impl<Args> Clone for PostgresStorage<Args>
impl<Args> Clone for PostgresStorage<Args>
Source§impl<Args> FetchById for PostgresStorage<Args>
impl<Args> FetchById for PostgresStorage<Args>
Source§impl<Args> ListAllTasks for PostgresStorage<Args>
impl<Args> ListAllTasks for PostgresStorage<Args>
Source§impl<Args> ListQueues for PostgresStorage<Args>
impl<Args> ListQueues for PostgresStorage<Args>
Source§impl<Args> ListTasks for PostgresStorage<Args>
impl<Args> ListTasks for PostgresStorage<Args>
Source§impl<Args: Sync> ListWorkers for PostgresStorage<Args>
impl<Args: Sync> ListWorkers for PostgresStorage<Args>
Source§fn list_workers(
&self,
) -> impl Future<Output = Result<Vec<RunningWorker>, Self::Error>> + Send
fn list_workers( &self, ) -> impl Future<Output = Result<Vec<RunningWorker>, Self::Error>> + Send
Source§fn list_all_workers(
&self,
) -> impl Future<Output = Result<Vec<RunningWorker>, Self::Error>> + Send
fn list_all_workers( &self, ) -> impl Future<Output = Result<Vec<RunningWorker>, Self::Error>> + Send
Source§impl<Args> Metrics for PostgresStorage<Args>
impl<Args> Metrics for PostgresStorage<Args>
Source§impl<Args> Sink<Task<Vec<u8>>> for PostgresStorage<Args>
impl<Args> Sink<Task<Vec<u8>>> for PostgresStorage<Args>
Source§fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>>
fn poll_ready( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Result<(), Self::Error>>
Sink to receive a value. Read moreSource§fn start_send(self: Pin<&mut Self>, item: PgTask) -> Result<(), Self::Error>
fn start_send(self: Pin<&mut Self>, item: PgTask) -> Result<(), Self::Error>
poll_ready which returned Poll::Ready(Ok(())). Read moreimpl<'pin, Args> Unpin for PostgresStorage<Args>where
PinnedFieldsOf<__PostgresStorage<'pin, Args>>: Unpin,
Source§impl<O: 'static + Send, Args> WaitForCompletion<O> for PostgresStorage<Args>
impl<O: 'static + Send, Args> WaitForCompletion<O> for PostgresStorage<Args>
Source§type ResultStream = Pin<Box<dyn Stream<Item = Result<TaskResult<O>, <PostgresStorage<Args> as Backend>::Error>> + Send>>
type ResultStream = Pin<Box<dyn Stream<Item = Result<TaskResult<O>, <PostgresStorage<Args> as Backend>::Error>> + Send>>
Source§fn wait_for(
&self,
task_ids: impl IntoIterator<Item = TaskId>,
) -> Self::ResultStream
fn wait_for( &self, task_ids: impl IntoIterator<Item = TaskId>, ) -> Self::ResultStream
Source§fn check_status(
&self,
task_ids: impl IntoIterator<Item = TaskId> + Send,
) -> impl Future<Output = Result<Vec<TaskResult<O>>, Self::Error>> + Send
fn check_status( &self, task_ids: impl IntoIterator<Item = TaskId> + Send, ) -> impl Future<Output = Result<Vec<TaskResult<O>>, Self::Error>> + Send
Source§fn wait_for_single(&self, task_id: TaskId) -> Self::ResultStream
fn wait_for_single(&self, task_id: TaskId) -> Self::ResultStream
Auto Trait Implementations§
impl<Args> !Freeze for PostgresStorage<Args>
impl<Args> !RefUnwindSafe for PostgresStorage<Args>
impl<Args> !UnwindSafe for PostgresStorage<Args>
impl<Args> Send for PostgresStorage<Args>where
PhantomData<Args>: Send,
impl<Args> Sync for PostgresStorage<Args>where
PhantomData<Args>: Sync,
impl<Args> UnsafeUnpin for PostgresStorage<Args>where
PhantomData<Args>: UnsafeUnpin,
Blanket Implementations§
Source§impl<B> BackendExt for Bwhere
B: Backend,
impl<B> BackendExt for Bwhere
B: Backend,
Source§fn poll_next_args(
&mut self,
cx: &mut Context<'_>,
worker: &WorkerContext,
) -> Poll<Option<Result<Task<Self::Args>, PollNextArgsError<Self>>>>
fn poll_next_args( &mut self, cx: &mut Context<'_>, worker: &WorkerContext, ) -> Poll<Option<Result<Task<Self::Args>, PollNextArgsError<Self>>>>
poll_next and decoding the Args in one step,
returning a Task<Self::Args, ..> instead of Task<Self::Compact, ..>.Source§fn pipe_to<Dst>(self, backend: Dst) -> Pipe<Dst, Self>where
Self: Sized,
fn pipe_to<Dst>(self, backend: Dst) -> Pipe<Dst, Self>where
Self: Sized,
sink Read moreSource§fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
F to be run on each error produced while polling the backend.Source§fn map_err<F, E2>(self, f: F) -> MapErr<Self, F>
fn map_err<F, E2>(self, f: F) -> MapErr<Self, F>
Self::Error into E2, useful for
heterogeneous composed backends.Source§fn with_codec<NewCodec>(self, codec: NewCodec) -> WithCodec<Self, NewCodec>
fn with_codec<NewCodec>(self, codec: NewCodec) -> WithCodec<Self, NewCodec>
Source§fn poll_with_stream<S>(self, stream: S) -> PollWith<Self, StreamStrategy<S>>
fn poll_with_stream<S>(self, stream: S) -> PollWith<Self, StreamStrategy<S>>
Source§fn poll_with_interval(
self,
duration: Duration,
) -> PollWith<Self, IntervalStrategy>where
Self: Sized,
fn poll_with_interval(
self,
duration: Duration,
) -> PollWith<Self, IntervalStrategy>where
Self: Sized,
Source§fn poll_with_backoff(
self,
interval: Duration,
config: BackoffConfig,
) -> PollWith<Self, BackoffStrategy>where
Self: Sized,
fn poll_with_backoff(
self,
interval: Duration,
config: BackoffConfig,
) -> PollWith<Self, BackoffStrategy>where
Self: Sized,
Source§fn poll_with_strategy<S>(self, strategy: S) -> PollWith<Self, S>where
Self: Sized,
S: PollStrategy,
fn poll_with_strategy<S>(self, strategy: S) -> PollWith<Self, S>where
Self: Sized,
S: PollStrategy,
Source§fn before_start<F, Fut>(self, f: F) -> BeforeStart<Self, Self::Error>
fn before_start<F, Fut>(self, f: F) -> BeforeStart<Self, Self::Error>
poll_ready is delegated.Source§fn before_stop<F, Fut>(self, f: F) -> BeforeStop<Self, Self::Error>
fn before_stop<F, Fut>(self, f: F) -> BeforeStop<Self, Self::Error>
Source§fn after_start<F, Fut>(self, f: F) -> AfterStart<Self, Self::Error>
fn after_start<F, Fut>(self, f: F) -> AfterStart<Self, Self::Error>
poll_ready is successful.Source§fn after_stop<F, Fut>(self, f: F) -> AfterStop<Self, Self::Error>
fn after_stop<F, Fut>(self, f: F) -> AfterStop<Self, Self::Error>
Source§fn interleave<S>(self, stream: S) -> Interleave<Self, S>
fn interleave<S>(self, stream: S) -> Interleave<Self, S>
Source§fn wake_on_push(self) -> WakeOnPush<Self>where
Self: Sized,
fn wake_on_push(self) -> WakeOnPush<Self>where
Self: Sized,
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<B, Args, Kind> Expose<Args, Kind> for Bwhere
B: Backend + Metrics + ListWorkers + ListQueues + ListAllTasks + ListTasks + TaskSink<Args, Kind>,
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 moreSource§impl<T, Item> SinkExt<Item> for T
impl<T, Item> SinkExt<Item> for T
Source§fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F>
fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F>
Source§fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F>
fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F>
Source§fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F>
fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F>
Source§fn sink_err_into<E>(self) -> SinkErrInto<Self, Item, E>
fn sink_err_into<E>(self) -> SinkErrInto<Self, Item, E>
Into trait. Read moreSource§fn buffer(self, capacity: usize) -> Buffer<Self, Item>where
Self: Sized,
fn buffer(self, capacity: usize) -> Buffer<Self, Item>where
Self: Sized,
Source§fn flush(&mut self) -> Flush<'_, Self, Item> ⓘwhere
Self: Unpin,
fn flush(&mut self) -> Flush<'_, Self, Item> ⓘwhere
Self: Unpin,
Source§fn send(&mut self, item: Item) -> Send<'_, Self, Item> ⓘwhere
Self: Unpin,
fn send(&mut self, item: Item) -> Send<'_, Self, Item> ⓘwhere
Self: Unpin,
Source§fn feed(&mut self, item: Item) -> Feed<'_, Self, Item> ⓘwhere
Self: Unpin,
fn feed(&mut self, item: Item) -> Feed<'_, Self, Item> ⓘwhere
Self: Unpin,
Source§fn send_all<'a, St>(&'a mut self, stream: &'a mut St) -> SendAll<'a, Self, St> ⓘ
fn send_all<'a, St>(&'a mut self, stream: &'a mut St) -> SendAll<'a, Self, St> ⓘ
Source§fn right_sink<Si1>(self) -> Either<Si1, Self> ⓘ
fn right_sink<Si1>(self) -> Either<Si1, Self> ⓘ
Source§fn poll_ready_unpin(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>>where
Self: Unpin,
fn poll_ready_unpin(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>>where
Self: Unpin,
Sink::poll_ready on Unpin
sink types.Source§fn start_send_unpin(&mut self, item: Item) -> Result<(), Self::Error>where
Self: Unpin,
fn start_send_unpin(&mut self, item: Item) -> Result<(), Self::Error>where
Self: Unpin,
Sink::start_send on Unpin
sink types.