grafos_jobs/
lib.rs

1//! grafos-jobs — Idempotent burst compute and retry scaffolding.
2//!
3//! This crate provides a higher-level job runner on top of `grafos-batch`.
4//! It standardizes chunking, idempotent output capture, retries on lease
5//! failure, and teardown semantics — the "pop-up supercomputer" pattern.
6//!
7//! # Core types
8//!
9//! | Type | Purpose |
10//! |------|---------|
11//! | [`WorkChunk`] | Trait for serializable work units with stable IDs |
12//! | [`JobOutputStore`] | Trait for storing/retrieving outputs by chunk ID |
13//! | [`RetryPolicy`] | Configures which errors to retry, max retries, backoff |
14//! | [`JobCoordinator`] | Orchestrates chunk execution with retries and aggregation |
15//!
16//! # Quick start
17//!
18//! ```rust
19//! use grafos_jobs::*;
20//!
21//! // Define a work chunk
22//! #[derive(Clone, serde::Serialize, serde::Deserialize)]
23//! struct Square { value: u64 }
24//!
25//! impl WorkChunk for Square {
26//!     fn chunk_id(&self) -> ChunkId { ChunkId(self.value) }
27//!     fn to_bytes(&self) -> Vec<u8> {
28//!         postcard::to_allocvec(self).unwrap()
29//!     }
30//!     fn from_bytes(bytes: &[u8]) -> grafos_std::Result<Self> {
31//!         postcard::from_bytes(bytes).map_err(|_| grafos_std::FabricError::IoError(-200))
32//!     }
33//! }
34//!
35//! // Create a job
36//! let chunks: Vec<Box<dyn WorkChunk>> = vec![
37//!     Box::new(Square { value: 2 }),
38//!     Box::new(Square { value: 3 }),
39//! ];
40//!
41//! let mut store = MemoryOutputStore::new();
42//! let policy = RetryPolicy::default();
43//!
44//! let mut coord = JobCoordinator::new(policy);
45//! let result = coord.run(
46//!     &chunks,
47//!     &mut store,
48//!     |chunk_bytes| {
49//!         let sq: Square = postcard::from_bytes(chunk_bytes)
50//!             .map_err(|_| grafos_std::FabricError::IoError(-200))?;
51//!         let result = sq.value * sq.value;
52//!         Ok(postcard::to_allocvec(&result).unwrap())
53//!     },
54//!     |outputs| {
55//!         let sum: u64 = outputs.iter().map(|(_, v)| {
56//!             postcard::from_bytes::<u64>(v).unwrap_or(0)
57//!         }).sum();
58//!         postcard::to_allocvec(&sum).unwrap()
59//!     },
60//! ).unwrap();
61//!
62//! let total: u64 = postcard::from_bytes(&result.aggregate).unwrap();
63//! assert_eq!(total, 4 + 9);
64//! ```
65//!
66//! # Feature flags
67//!
68//! | Feature | Default | Effect |
69//! |---------|---------|--------|
70//! | `std` | Yes | Enables `std` in dependent crates |
71//! | `observe` | No | Enables `grafos-observe` hooks |
72
73#![cfg_attr(not(feature = "std"), no_std)]
74
75extern crate alloc;
76
77mod coordinator;
78mod output_store;
79mod retry;
80mod work_chunk;
81
82pub use coordinator::{JobCoordinator, JobResult};
83pub use output_store::{JobOutputStore, MemoryOutputStore};
84pub use retry::{RetryPolicy, RetryableError};
85pub use work_chunk::{ChunkId, WorkChunk};