Skip to main content

pharos_runtime_core/
readiness.rs

1use std::path::Path;
2
3use crate::config::AppRuntime;
4
5/// Returns true when one loaded app has enough local runtime state to be considered ready.
6pub fn app_runtime_probe_ready(app: &AppRuntime, uses_relational_runtime_authority: bool) -> bool {
7    if app.host_profile.as_deref() != Some("dynamic-app") {
8        return true;
9    }
10    if uses_relational_runtime_authority {
11        return true;
12    }
13    app.state_path
14        .as_deref()
15        .filter(|value| !value.is_empty())
16        .is_some_and(|path| Path::new(path).exists())
17}
18
19/// Returns true when a loaded runtime stack has no failed apps, at least one app, and every app is ready.
20pub fn runtime_stack_probe_ready<'a>(
21    apps: impl IntoIterator<Item = &'a AppRuntime>,
22    failed_app_count: usize,
23    mut app_ready: impl FnMut(&'a AppRuntime) -> bool,
24) -> bool {
25    if failed_app_count != 0 {
26        return false;
27    }
28    let mut seen_app = false;
29    for app in apps {
30        seen_app = true;
31        if !app_ready(app) {
32            return false;
33        }
34    }
35    seen_app
36}
37
38#[cfg(test)]
39mod tests {
40    use super::{app_runtime_probe_ready, runtime_stack_probe_ready};
41    use crate::config::AppRuntime;
42
43    #[test]
44    fn readiness_distinguishes_liveness_from_full_app_availability() {
45        let dynamic_missing_state = AppRuntime {
46            host_profile: Some("dynamic-app".to_owned()),
47            state_path: Some("/path/that/does/not/exist/pharos-state.json".to_owned()),
48            ..AppRuntime::default()
49        };
50        assert!(!app_runtime_probe_ready(&dynamic_missing_state, false));
51        assert!(app_runtime_probe_ready(&dynamic_missing_state, true));
52        assert!(!runtime_stack_probe_ready(
53            [dynamic_missing_state.clone()].iter(),
54            1,
55            |app| app_runtime_probe_ready(app, true)
56        ));
57    }
58}