use trusty_memory::AppState;
pub(crate) fn spawn_startup_tasks(state: &AppState) {
let (dtx, dream_shutdown_rx) = trusty_memory::dream_scheduler::make_shutdown_watch();
let warmup_state = state.clone();
tokio::spawn(async move {
let ws = std::time::Instant::now();
tracing::info!("starting background embedder warm-up (issues #906/#910)");
match trusty_common::memory_core::retrieval::shared_embedder().await {
Ok(_) => {
let elapsed_ms = ws.elapsed().as_millis() as u64;
tracing::info!(
elapsed_ms,
"background embedder warm-up complete; daemon is now Ready (issues #910/#911)"
);
warmup_state.set_ready();
}
Err(e) => tracing::error!(
elapsed_ms = ws.elapsed().as_millis() as u64,
"background embedder warm-up failed (daemon stays Warming; \
memory ops will return a bounded error on first request): {e:#}"
),
}
});
let bg_state = state.clone();
tokio::spawn(async move {
let started = std::time::Instant::now();
tracing::info!("starting background palace hydration");
match bg_state.load_palaces_from_disk().await {
Ok(count) => tracing::info!(
elapsed_ms = started.elapsed().as_millis() as u64,
"background palace hydration complete: {count} palaces loaded"
),
Err(e) => tracing::error!(
elapsed_ms = started.elapsed().as_millis() as u64,
"background palace hydration failed: {e:#}"
),
}
let n = trusty_memory::dream_scheduler::spawn_background_maintenance(
&bg_state.registry,
dream_shutdown_rx,
dtx,
);
tracing::info!(loops = n, "dream_scheduler: {n} loop(s) running (#1529)");
trusty_memory::bm25_backfill::spawn_startup_backfill(&bg_state);
trusty_memory::bm25_repair::spawn_repair_sweep(&bg_state);
if let Some(palace) = bg_state.default_palace.clone() {
if let Ok(cwd) = std::env::current_dir() {
bg_state.spawn_alias_discovery(palace, cwd);
}
}
{
let update_available = bg_state.update_available.clone();
tokio::spawn(async move {
let crate_name = env!("CARGO_PKG_NAME");
let current = env!("CARGO_PKG_VERSION");
if let Some(info) =
trusty_common::update::check_throttled(crate_name, current).await
{
tracing::info!(
latest = %info.latest,
"update available: {}",
trusty_common::update::notice(&info)
);
eprintln!("{}", trusty_common::update::notice(&info));
if let Ok(mut guard) = update_available.lock() {
*guard = Some(info.latest);
}
}
});
}
let pin_scan_started = std::time::Instant::now();
let pin_map_ref = bg_state.pin_project_map.clone();
let override_active = trusty_memory::is_data_dir_override_active();
let scan_result = tokio::task::spawn_blocking(move || {
let search_dirs = if override_active {
Vec::new()
} else {
trusty_memory::startup_scan::default_search_dirs()
};
trusty_memory::startup_scan::scan_pin_map(&search_dirs)
})
.await;
match scan_result {
Ok(map) => {
let count = map.len();
let elapsed_ms = pin_scan_started.elapsed().as_millis() as u64;
for (palace_id, project_path) in map {
pin_map_ref.insert(palace_id, project_path);
}
tracing::info!(
pins_found = count,
elapsed_ms,
"startup pin scan complete: {count} pin(s) discovered in {elapsed_ms}ms"
);
eprintln!("startup pin scan complete: {count} pin(s) discovered in {elapsed_ms}ms");
}
Err(e) => {
tracing::warn!("startup pin scan task panicked or was cancelled: {e}");
eprintln!("startup pin scan task panicked or was cancelled: {e}");
}
}
});
}