Releases: balena-io-modules/mahler-rs
Release list
v0.25.12
v0.25.11
v0.25.10
01366ac (Fix task error rollback, 2026-03-21)
v0.25.9
Add View::commit method
The method, like View::flush communicates changes back to the worker, however, it also created a new rollback checkpoint at the commit state. This is useful for creating changes that must persist after failure of a given task.
Example
use mahler::{
error::Error,
extract::View,
task::{with_io, IO},
job::update,
worker::Worker,
};
fn process_items(mut view: View<Vec<String>>) -> IO<Vec<String>> {
with_io(view, |mut view| async move {
// Process items one at a time, flushing after each
for i in 0..10 {
view.push(format!("item_{}", i));
// Do some I/O work
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
// A processed item persists after this point
let _ = view.commit().await;
}
Ok(view)
})
}List of commits
6b6d72c (Add View::commit method, 2026-03-18)
v0.25.8
v0.25.7
fa386ba (Create runtime::Id type for handler id uniqueness, 2026-03-10)
v0.25.6
Add descriptions to exceptions and refactor planner
-
Exception descriptions: Exceptions now support an optional description via
with_description(), in the same way that descriptions can be defined for Jobs. The description is returned as part of the workflow's ignored operations.worker .job("/services/{service}", update(update_service)) .exception( "/services/{service}", exception::update(skip_failed).with_description( |Args(s): Args<String>| format!("service '{s}' is failed"), ), );Ignored operations are now returned as
Ignored { operation, reason }fromWorkflow::exceptions(), wherereasoncontains the exception description if one was set. -
Planner refactor: the planner module has been split into smaller files (
candidate.rs,search.rs,path_utils.rs,task_workflow.rs) for readability, and search/merge operations have been optimized to avoid unnecessary clones.
List of commits
5608055 (Move Descripton to mahler crate root, 2026-03-03)
6fb58da (Add description field to Exceptions, 2026-03-05)
12a220c (Refactor the planner module, 2026-03-05)
ebab3c7 (Efficiency improvements to planner, 2026-03-05)
757777d (Fix worker doc failure, 2026-03-05)
v0.25.5
ff016c4 (Allow exceptions on the last iteration of the planner, 2026-02-23)
v0.25.4
Fix bug with DAG::reverse method
Reversing nested forks in some cases was resulting in all branches being nested into the inner-most fork. This PR fixes the issue and refactors other DAG methods for efficiency.
Additionally removes empty branch tracing information during planning.
List of commits
0c0ba57 (Add test case for a DAG with nested forks, 2026-02-19)
c634a01 (Fix bug with DAG::reverse merging fork branches, 2026-02-19)
01518c3 (Simplify DAG Display and Iterator implementations, 2026-02-19)
c74e654 (Remove tracing information from planning on empty task, 2026-02-19)
v0.25.3
Add SystemTarget extractor
-
Adds
SystemTarget<T>extractor that provides access to the full target state passed to the worker, as opposed toTarget<T>which resolves to the value
at the task's scoped path- The global target is now automatically propagated to child tasks in methods, so
.with_target()is no longer needed when forwarding the same target - Adds
target_overridetoContextto distinguish between the global target and an explicit override viawith_target()
Example
SystemTargetis useful when a task scoped to a sub-path needs to inspect the full target state:use mahler::state::{State, Map}; use mahler::extract::{View, Target, SystemTarget}; use mahler::task::IO; #[derive(State)] struct App { services: Map<String, Service>, } #[derive(State)] struct Service { image: String, running: bool, } // This task is scoped to a single service via "/{service}" // `Target` gives the target for this specific service // `SystemTarget` gives the full App target fn start_service( mut svc: View<Service>, Target(tgt): Target<Service>, SystemTarget(app_tgt): SystemTarget<App>, ) { // Use the scoped target for this service svc.running = tgt.running; // Use the system target to check other services, // e.g. to coordinate dependencies across services let total_services = app_tgt.services.len(); // ... }
- The global target is now automatically propagated to child tasks in methods, so
Methods no longer need .with_target() to forward the target to child tasks:
```rust
// Before
fn my_method(Target(tgt): Target<i32>) -> Vec<Task> {
vec![child_task.with_target(tgt)]
}
// After - global target is propagated automatically
fn my_method() -> Vec<Task> {
vec![child_task.into_task()]
}
List of commits
a2f3b8a (Add SystemTarget extractor, 2026-02-18)