actionqueue_workflow/children.rs
1//! Dispatch-time snapshot building for child task states.
2//!
3//! The re-exported types from `actionqueue-executor-local` are the canonical
4//! snapshot types; this module provides the builder that queries the projection
5//! to construct them.
6
7use actionqueue_core::ids::TaskId;
8pub use actionqueue_executor_local::children::{ChildState, ChildrenSnapshot};
9use actionqueue_storage::recovery::reducer::ReplayReducer;
10
11/// Builds a [`ChildrenSnapshot`] by querying the projection for all tasks
12/// whose `parent_task_id` matches `parent_id`.
13///
14/// Returns `None` if there are no children (avoids allocating an empty snapshot).
15/// Returns `Some(snapshot)` with all child run states at the current projection
16/// sequence — this is an immutable point-in-time view safe to pass to handlers
17/// running on `spawn_blocking`.
18pub fn build_children_snapshot(
19 projection: &ReplayReducer,
20 parent_id: TaskId,
21) -> Option<ChildrenSnapshot> {
22 let children: Vec<ChildState> = projection
23 .task_records()
24 .filter(|tr| tr.task_spec().parent_task_id() == Some(parent_id))
25 .map(|tr| {
26 let child_id = tr.task_spec().id();
27 let run_states: Vec<_> = projection
28 .run_instances()
29 .filter(|r| r.task_id() == child_id)
30 .map(|r| (r.id(), r.state()))
31 .collect();
32 ChildState::new(child_id, run_states)
33 })
34 .collect();
35
36 if children.is_empty() {
37 None
38 } else {
39 Some(ChildrenSnapshot::new(children))
40 }
41}