Skip to main content

solti_runner/
lib.rs

1//! # solti-runner
2//!
3//! Runner plugin interface, routing, and execution metrics for the solti task system.
4//!
5//! This crate defines how task executors (runners) are declared, selected, and
6//! observed. It sits between the domain model ([`solti_model`]) and the
7//! orchestration layer (`solti-core`), providing a stable plugin boundary.
8//!
9//! ## Architecture
10//!
11//! ```text
12//!  TaskSpec ──► RunnerRouter ──► Runner::build_task() ──► TaskRef
13//!                  │                    ▲
14//!                  │  label matching    │  BuildContext
15//!                  │  + supports()      │  (env + metrics)
16//!                  ▼                    │
17//!              RunnerEntry          MetricsHandle
18//!              (runner + labels)    (Arc<dyn MetricsBackend>)
19//! ```
20//!
21//! ## Public API
22//!
23//! | Item                  | Description                                                  |
24//! |-----------------------|--------------------------------------------------------------|
25//! | [`Runner`]            | Trait that concrete executors implement                      |
26//! | [`RunnerRouter`]      | Selects a runner for a given [`TaskSpec`](solti_model::TaskSpec) by `supports()` + label matching |
27//! | [`BuildContext`]      | Shared dependencies injected into runners (env + metrics)    |
28//! | [`RunId`]             | Human-readable run identifier (`{runner}-{slot}-{seq}`)      |
29//! | [`RunnerError`]       | Error type for runner operations                             |
30//! | [`MetricsBackend`]    | Trait for collecting task execution metrics                   |
31//! | [`MetricsHandle`]     | `Arc<dyn MetricsBackend>` — cloneable shared handle          |
32//! | [`NoOpMetrics`]       | Zero-size backend that compiles to nothing                   |
33//! | [`RunnerType`]        | Metric label: `Subprocess`, `Wasm`, `Container`              |
34//! | [`TaskOutcome`]       | Metric label: `Success`, `Failure`, `Canceled`, `Timeout`    |
35//!
36//! ## Runner implementation
37//!
38//! A runner must implement [`Runner`] and be registered in a [`RunnerRouter`]:
39//!
40//! ```text
41//! use solti_runner::{Runner, RunnerError, BuildContext, RunId};
42//! use solti_model::TaskSpec;
43//! use taskvisor::TaskRef;
44//!
45//! struct MyRunner;
46//!
47//! impl Runner for MyRunner {
48//!     fn name(&self) -> &'static str { "my-runner" }
49//!
50//!     fn supports(&self, spec: &TaskSpec) -> bool {
51//!         matches!(spec.kind(), solti_model::TaskKind::Subprocess(_))
52//!     }
53//!
54//!     fn build_task(&self, spec: &TaskSpec, ctx: &BuildContext) -> Result<TaskRef, RunnerError> {
55//!         // build and return a TaskRef
56//!         todo!()
57//!     }
58//! }
59//! ```
60//!
61//! ## Routing
62//!
63//! [`RunnerRouter`] selects the first registered runner that:
64//! 1. returns `true` from [`Runner::supports`] for the given spec, and
65//! 2. satisfies the [`RunnerSelector`](solti_model::RunnerSelector) label constraints (if any).
66//!
67//! ```text
68//! use solti_runner::{RunnerRouter, BuildContext};
69//!
70//! let mut router = RunnerRouter::new();
71//! router.register(Arc::new(MyRunner));
72//!
73//! let task_ref = router.build(&spec)?;
74//! ```
75//!
76//! ## Metrics
77//!
78//! Metrics are collected via [`MetricsBackend`], injected through [`BuildContext`].
79//! The default is [`NoOpMetrics`] (zero-cost). Backends like `solti-prometheus`
80//! implement [`MetricsBackend`] for production use.
81//!
82//! ## Also
83//!
84//! - [`solti_model`] — domain types consumed by runners ([`TaskSpec`](solti_model::TaskSpec), [`TaskKind`](solti_model::TaskKind)).
85//! - [`taskvisor::TaskRef`] — the concrete task handle returned by [`Runner::build_task`].
86//! - `solti-exec` — subprocess runner implementation.
87//! - `solti-prometheus` — Prometheus [`MetricsBackend`] implementation.
88
89mod error;
90pub use error::RunnerError;
91
92mod runner;
93pub use runner::Runner;
94
95mod context;
96pub use context::BuildContext;
97
98mod id;
99pub use id::{RunId, make_run_id};
100
101mod router;
102pub use router::RunnerRouter;
103
104pub mod metrics;
105pub use metrics::{
106    MetricsBackend, MetricsHandle, NoOpMetrics, RunnerType, TaskOutcome, noop_metrics,
107};