Skip to main content

runledger_runtime/
lib.rs

1//! Async runtime loops for executing Runledger jobs against a persistence
2//! backend.
3//!
4//! Use this crate to wire the operational pieces around `runledger-core`
5//! handlers and `runledger-postgres` storage:
6//! - [`Supervisor`] starts and joins the worker, scheduler, and reaper loops
7//!   for a typical worker process
8//! - [`catalog::JobCatalog`] is the preferred startup API for handler
9//!   registration, definition sync, and catalog-validated enqueue helpers
10//! - [`registry::JobRegistry`] stores concrete handlers directly for advanced
11//!   setups that manage definitions separately
12//! - [`config::JobsConfig`] centralizes poll, lease, and concurrency settings
13//!
14//! A typical service builds a shared PostgreSQL pool, registers handlers in a
15//! [`catalog::JobCatalog`], syncs definitions during startup, and starts a
16//! [`Supervisor`] with [`SupervisorBuilder::with_catalog`]. Worker processes
17//! should call [`Supervisor::run_until_shutdown`] to observe task failures while
18//! still applying a bounded shutdown deadline. Use
19//! [`Supervisor::shutdown_with_timeout`] when shutdown is signaled externally, or
20//! [`Supervisor::shutdown`] when the caller already has an external shutdown
21//! budget or knows all loops will exit promptly.
22//!
23//! The lower-level [`worker::run_worker_loop`], [`scheduler::run_scheduler_loop`],
24//! and [`reaper::run_reaper_loop`] functions remain public for custom process
25//! orchestration, but [`Supervisor`] is the preferred runtime facade.
26//!
27//! # Copy-Paste Examples
28//!
29//! - [Run a worker binary](https://github.com/featherenvy/runledger/blob/master/runledger-runtime/examples/worker_binary.rs)
30//! - [Enqueue one job](https://github.com/featherenvy/runledger/blob/master/runledger-postgres/examples/enqueue_job.rs)
31//! - [Enqueue a workflow DAG](https://github.com/featherenvy/runledger/blob/master/runledger-postgres/examples/workflow_dag.rs)
32//! - [Use an external workflow gate](https://github.com/featherenvy/runledger/blob/master/runledger-postgres/examples/external_gate.rs)
33//! - [Create a scheduled job entrypoint](https://github.com/featherenvy/runledger/blob/master/runledger-postgres/examples/schedule_job.rs)
34//!
35//! # Prelude
36//!
37//! ```rust
38//! use runledger_runtime::prelude::*;
39//! ```
40//!
41//! The runtime prelude exports the worker-process facade and configuration
42//! types. Import `runledger_core::prelude::*` for handler contracts and
43//! `runledger_postgres::prelude::*` for persistence APIs.
44//!
45//! # Run A Worker Process
46//!
47//! ```rust,no_run
48//! # async fn demo(
49//! #     pool: runledger_postgres::DbPool,
50//! # ) -> std::result::Result<(), Box<dyn std::error::Error>> {
51//! use std::time::Duration;
52//!
53//! use runledger_core::prelude::*;
54//! use runledger_runtime::prelude::*;
55//!
56//! struct MyHandler;
57//! # #[async_trait::async_trait]
58//! # impl JobHandler for MyHandler {
59//! #     fn job_type(&self) -> JobType<'static> { JobType::new("jobs.example") }
60//! #     async fn execute(
61//! #         &self,
62//! #         _context: JobContext,
63//! #         _payload: serde_json::Value,
64//! #     ) -> std::result::Result<(), JobFailure> { Ok(()) }
65//! # }
66//!
67//! let catalog = JobCatalog::new().job("jobs.example", MyHandler);
68//! catalog.sync_definitions(&pool).await?;
69//! let supervisor = Supervisor::builder(&pool, JobsConfig::from_env())?
70//!     .with_catalog(&catalog)
71//!     .build()?;
72//!
73//! supervisor
74//!     .run_until_shutdown(std::future::pending::<()>(), Duration::from_secs(30))
75//!     .await?;
76//! # Ok(())
77//! # }
78//! ```
79//!
80//! Use [`Supervisor::run_until_shutdown`] for ordinary worker binaries so the
81//! process observes internal runtime task failures while still applying a
82//! bounded shutdown deadline. Use the lower-level loop functions only for custom
83//! process orchestration.
84
85pub mod catalog;
86pub mod config;
87pub mod error;
88pub mod reaper;
89pub mod registry;
90pub mod scheduler;
91pub mod supervisor;
92pub mod worker;
93
94pub use error::{Error, ReaperError, Result, RuntimeError, SchedulerError, WorkerError};
95pub use supervisor::{Supervisor, SupervisorBuilder, SupervisorShutdown};
96
97/// Common `runledger-runtime` imports for worker-process integration.
98///
99/// This prelude avoids generic `Result` or `Error` aliases so it can be
100/// glob-imported alongside the core and PostgreSQL preludes.
101pub mod prelude {
102    pub use crate::catalog::{
103        CatalogError, CatalogJobEnqueueInput, CatalogJobScheduleInput, CatalogWorkflowDagBuilder,
104        JobCatalog, JobCatalogDefaults, JobCatalogExactSyncReport, JobCatalogSyncReport,
105        JobCatalogSyncScope,
106    };
107    pub use crate::config::JobsConfig;
108    pub use crate::error::{ReaperError, RuntimeError, SchedulerError, WorkerError};
109    pub use crate::registry::JobRegistry;
110    pub use crate::{RuntimeLoopExit, Supervisor, SupervisorBuilder, SupervisorShutdown};
111}
112
113/// Reason a low-level runtime loop exited.
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
115pub enum RuntimeLoopExit {
116    /// The loop observed a shutdown request or a closed shutdown channel.
117    Shutdown,
118    /// The loop completed without observing shutdown. Supervisors treat this as
119    /// an unexpected task exit.
120    Completed,
121}
122
123#[cfg(test)]
124#[path = "../test_support.rs"]
125pub(crate) mod test_support;