commit 59b792f10147bf9bf41bf4d24da503e2935f76df
parent 0939774c7546d79bbc28ba5317140fc17fc0d1fe
Author: triesap <triesap@radroots.dev>
Date: Wed, 21 Jan 2026 15:55:49 +0000
app: parallelize health checks
- read app state once for permission and key checks
- run health checks concurrently with futures join
- keep per-check log start/end markers
- add unit test for provided state helper
Diffstat:
| M | app/src/health.rs | | | 90 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
1 file changed, 66 insertions(+), 24 deletions(-)
diff --git a/app/src/health.rs b/app/src/health.rs
@@ -93,7 +93,9 @@ use crate::{
RadrootsAppLogLevel,
RadrootsAppTangleClient,
RadrootsAppKeyMapConfig,
+ RadrootsAppState,
};
+use futures::join;
use radroots_app_core::notifications::RadrootsClientNotificationsPermission;
use radroots_app_core::datastore::{RadrootsClientDatastore, RadrootsClientDatastoreError};
use radroots_app_core::keystore::{RadrootsClientKeystoreError, RadrootsClientKeystoreNostr};
@@ -152,11 +154,25 @@ pub async fn app_health_check_state_active_key<T: RadrootsClientDatastore>(
datastore: &T,
key_maps: &RadrootsAppKeyMapConfig,
) -> RadrootsAppHealthCheckResult {
- let app_data = match app_datastore_read_state(datastore, key_maps).await {
- Ok(value) => value,
- Err(err) => return RadrootsAppHealthCheckResult::error(err.to_string()),
+ app_health_check_state_active_key_with_state(datastore, key_maps, None).await
+}
+
+async fn app_health_check_state_active_key_with_state<T: RadrootsClientDatastore>(
+ datastore: &T,
+ key_maps: &RadrootsAppKeyMapConfig,
+ state: Option<&RadrootsAppState>,
+) -> RadrootsAppHealthCheckResult {
+ let active_key = match state {
+ Some(value) => value.active_key.clone(),
+ None => {
+ let app_data = match app_datastore_read_state(datastore, key_maps).await {
+ Ok(value) => value,
+ Err(err) => return RadrootsAppHealthCheckResult::error(err.to_string()),
+ };
+ app_data.active_key
+ }
};
- if app_data.active_key.is_empty() {
+ if active_key.is_empty() {
return RadrootsAppHealthCheckResult::error("missing");
}
let key_name = match app_datastore_key_nostr_key(key_maps) {
@@ -168,7 +184,7 @@ pub async fn app_health_check_state_active_key<T: RadrootsClientDatastore>(
Err(RadrootsClientDatastoreError::NoResult) => return RadrootsAppHealthCheckResult::error("missing"),
Err(err) => return RadrootsAppHealthCheckResult::error(err.to_string()),
};
- if stored != app_data.active_key {
+ if stored != active_key {
return RadrootsAppHealthCheckResult::error("mismatch");
}
RadrootsAppHealthCheckResult::ok()
@@ -272,31 +288,39 @@ pub async fn app_health_check_all<T: RadrootsClientDatastore, K: RadrootsClientK
let key_maps_result = app_health_check_key_maps(key_maps);
log_health_end("key_maps", &key_maps_result);
log_health_start("bootstrap_settings");
- let bootstrap_settings = app_health_check_bootstrap_settings(datastore, key_maps).await;
- log_health_end("bootstrap_settings", &bootstrap_settings);
log_health_start("bootstrap_state");
- let bootstrap_state = app_health_check_bootstrap_state(datastore, key_maps).await;
- log_health_end("bootstrap_state", &bootstrap_state);
log_health_start("state_active_key");
- let state_active_key = app_health_check_state_active_key(datastore, key_maps).await;
- log_health_end("state_active_key", &state_active_key);
log_health_start("notifications");
- let stored_permission = app_datastore_read_state(datastore, key_maps)
- .await
- .ok()
- .and_then(|data| data.notifications_permission);
- let notifications_result =
- app_health_check_notifications_with_state(notifications, stored_permission.as_deref())
- .await;
- log_health_end("notifications", ¬ifications_result);
log_health_start("tangle");
- let tangle_result = app_health_check_tangle(tangle);
- log_health_end("tangle", &tangle_result);
log_health_start("datastore_roundtrip");
- let datastore_roundtrip = app_health_check_datastore_roundtrip(datastore).await;
- log_health_end("datastore_roundtrip", &datastore_roundtrip);
log_health_start("keystore");
- let keystore_result = app_health_check_keystore_access(datastore, keystore, key_maps).await;
+ let stored_state = app_datastore_read_state(datastore, key_maps).await.ok();
+ let stored_permission = stored_state
+ .as_ref()
+ .and_then(|data| data.notifications_permission.as_deref());
+ let (
+ bootstrap_settings,
+ bootstrap_state,
+ state_active_key,
+ notifications_result,
+ tangle_result,
+ datastore_roundtrip,
+ keystore_result,
+ ) = join!(
+ app_health_check_bootstrap_settings(datastore, key_maps),
+ app_health_check_bootstrap_state(datastore, key_maps),
+ app_health_check_state_active_key_with_state(datastore, key_maps, stored_state.as_ref()),
+ app_health_check_notifications_with_state(notifications, stored_permission),
+ async { app_health_check_tangle(tangle) },
+ app_health_check_datastore_roundtrip(datastore),
+ app_health_check_keystore_access(datastore, keystore, key_maps),
+ );
+ log_health_end("bootstrap_settings", &bootstrap_settings);
+ log_health_end("bootstrap_state", &bootstrap_state);
+ log_health_end("state_active_key", &state_active_key);
+ log_health_end("notifications", ¬ifications_result);
+ log_health_end("tangle", &tangle_result);
+ log_health_end("datastore_roundtrip", &datastore_roundtrip);
log_health_end("keystore", &keystore_result);
RadrootsAppHealthReport {
key_maps: key_maps_result,
@@ -326,6 +350,7 @@ pub async fn app_health_check_all_logged<T: RadrootsClientDatastore, K: Radroots
mod tests {
use super::{
app_health_check_state_active_key,
+ app_health_check_state_active_key_with_state,
app_health_check_all,
app_health_check_all_logged,
app_health_check_key_maps,
@@ -707,6 +732,23 @@ mod tests {
}
#[test]
+ fn health_check_state_uses_provided_state() {
+ let mut state = crate::RadrootsAppState::default();
+ state.active_key = "pub".to_string();
+ let datastore = TestDatastore {
+ get_result: Ok("pub".to_string()),
+ app_data: None,
+ };
+ let key_maps = crate::app_key_maps_default();
+ let result = futures::executor::block_on(app_health_check_state_active_key_with_state(
+ &datastore,
+ &key_maps,
+ Some(&state),
+ ));
+ assert_eq!(result.status, RadrootsAppHealthCheckStatus::Ok);
+ }
+
+ #[test]
fn health_check_all_reports_idb_errors() {
let datastore = RadrootsClientWebDatastore::new(None);
let keystore = RadrootsClientWebKeystoreNostr::new(None);