11# apalis-sqlite
22
3- Background task processing for Rust using apalis and sqlite.
3+ Background task processing for Rust using ` apalis ` and ` sqlite ` .
44
55## Features
66
77- ** Reliable job queue** using SQLite as the backend.
88- ** Multiple storage types** : standard polling and event-driven (hooked) storage.
99- ** Custom codecs** for serializing/deserializing job arguments as bytes.
1010- ** Heartbeat and orphaned job re-enqueueing** for robust job processing.
11- - ** Integration with Apalis workers and middleware.**
11+ - ** Integration with ` apalis ` workers and middleware.**
1212
1313## Storage Types
1414
@@ -23,11 +23,17 @@ The naming is designed to clearly indicate the storage mechanism and its capabil
2323### Basic Worker Example
2424
2525``` rust,no_run
26+ use std::time::Duration;
27+
28+ use apalis::prelude::*;
29+ use apalis_sqlite::*;
30+ use futures::stream::{self, StreamExt};
31+
2632#[tokio::main]
2733async fn main() {
2834 let pool = SqlitePool::connect(":memory:").await.unwrap();
2935 SqliteStorage::setup(&pool).await.unwrap();
30- let mut backend = SqliteStorage::new(&pool); // With default config
36+ let mut backend = SqliteStorage::new(&pool);
3137
3238 let mut start = 0;
3339 let mut items = stream::repeat_with(move || {
@@ -36,10 +42,10 @@ async fn main() {
3642 .run_after(Duration::from_secs(1))
3743 .with_ctx(SqlContext::new().with_priority(1))
3844 .build();
39- Ok( task)
45+ task
4046 })
4147 .take(10);
42- backend.send_all (&mut items).await.unwrap();
48+ backend.push_all (&mut items).await.unwrap();
4349
4450 async fn send_reminder(item: usize, wrk: WorkerContext) -> Result<(), BoxDynError> {
4551 Ok(())
@@ -55,19 +61,24 @@ async fn main() {
5561### Hooked Worker Example (Event-driven)
5662
5763``` rust,no_run
64+ use std::time::Duration;
65+
66+ use apalis::prelude::*;
67+ use apalis_sqlite::*;
68+ use futures::stream::{self, StreamExt};
5869
5970#[tokio::main]
6071async fn main() {
61- let pool = SqlitePool::connect(":memory:").await.unwrap();
62- SqliteStorage::setup(&pool).await.unwrap();
63-
6472 let lazy_strategy = StrategyBuilder::new()
6573 .apply(IntervalStrategy::new(Duration::from_secs(5)))
6674 .build();
6775 let config = Config::new("queue")
6876 .with_poll_interval(lazy_strategy)
6977 .set_buffer_size(5);
70- let backend = SqliteStorage::new_with_callback(&pool, &config).await;
78+ let backend = SqliteStorage::new_with_callback(":memory:", &config);
79+
80+ let pool = backend.pool();
81+ SqliteStorage::setup(&pool).await.unwrap();
7182
7283 tokio::spawn({
7384 let pool = pool.clone();
@@ -77,7 +88,7 @@ async fn main() {
7788 let mut start = 0;
7889 let items = stream::repeat_with(move || {
7990 start += 1;
80- Task::builder(serde_json::to_value (&start).unwrap())
91+ Task::builder(serde_json::to_vec (&start).unwrap())
8192 .run_after(Duration::from_secs(1))
8293 .with_ctx(SqlContext::new().with_priority(start))
8394 .build()
@@ -103,32 +114,38 @@ async fn main() {
103114### Workflow Example
104115
105116``` rust,no_run
117+ use std::time::Duration;
118+
119+ use apalis::prelude::*;
120+ use apalis_sqlite::*;
121+ use apalis_workflow::*;
122+
106123#[tokio::main]
107124async fn main() {
108125 let workflow = Workflow::new("odd-numbers-workflow")
109- .then (|a: usize| async move {
110- Ok::<_, WorkflowError >((0..=a).collect::<Vec<_ >>())
126+ .and_then (|a: usize| async move {
127+ Ok::<Vec<usize>, BoxDynError >((0..=a).collect::<Vec<usize >>())
111128 })
112- .filter_map(|x| async move {
129+ .filter_map(|x: usize | async move {
113130 if x % 2 != 0 { Some(x) } else { None }
114131 })
115- .filter_map(|x| async move {
132+ .filter_map(|x: usize | async move {
116133 if x % 3 != 0 { Some(x) } else { None }
117134 })
118- .filter_map(|x| async move {
135+ .filter_map(|x: usize | async move {
119136 if x % 5 != 0 { Some(x) } else { None }
120137 })
121138 .delay_for(Duration::from_millis(1000))
122- .then (|a: Vec<usize>| async move {
139+ .and_then (|a: Vec<usize>| async move {
123140 println!("Sum: {}", a.iter().sum::<usize>());
124- Ok::<(), WorkflowError >(())
141+ Ok::<(), BoxDynError >(())
125142 });
126143
127144 let pool = SqlitePool::connect(":memory:").await.unwrap();
128145 SqliteStorage::setup(&pool).await.unwrap();
129146 let mut sqlite = SqliteStorage::new_in_queue(&pool, "test-workflow");
130147
131- sqlite.push (100usize).await.unwrap();
148+ sqlite.push_start (100usize).await.unwrap();
132149
133150 let worker = WorkerBuilder::new("rango-tango")
134151 .backend(sqlite)
@@ -144,6 +161,56 @@ async fn main() {
144161}
145162```
146163
164+ ### Shared Example
165+
166+ Full support for sharing the same connection. This example shows how to run multiple types with one function
167+
168+ ``` rust,no_run
169+ use std::{collections::HashMap, time::Duration};
170+
171+ use apalis::prelude::*;
172+ use apalis_sqlite::{SharedSqliteStorage, SqliteStorage};
173+
174+ use futures::stream;
175+
176+ #[tokio::main]
177+ async fn main() {
178+
179+ let mut store = SharedSqliteStorage::new(":memory:");
180+
181+ SqliteStorage::setup(store.pool()).await.unwrap();
182+
183+ let mut map_store = store.make_shared().unwrap();
184+
185+ let mut int_store = store.make_shared().unwrap();
186+
187+ map_store
188+ .push_stream(&mut stream::iter(vec![HashMap::<String, String>::new()]))
189+ .await
190+ .unwrap();
191+ int_store.push(99).await.unwrap();
192+
193+ async fn send_reminder<T, I>(
194+ _: T,
195+ _task_id: TaskId<I>,
196+ wrk: WorkerContext,
197+ ) -> Result<(), BoxDynError> {
198+ tokio::time::sleep(Duration::from_secs(2)).await;
199+ wrk.stop().unwrap();
200+ println!("Reminder sent!");
201+ Ok(())
202+ }
203+
204+ let int_worker = WorkerBuilder::new("rango-tango-2")
205+ .backend(int_store)
206+ .build(send_reminder);
207+ let map_worker = WorkerBuilder::new("rango-tango-1")
208+ .backend(map_store)
209+ .build(send_reminder);
210+ tokio::try_join!(int_worker.run(), map_worker.run()).unwrap();
211+ }
212+ ```
213+
147214## Observability
148215
149216You can track your jobs using [ apalis-board] ( https://github.com/apalis-dev/apalis-board ) .
0 commit comments