feat(catalog): reload manifest overlay when a refreshed catalog changes
load_manifests() only ran at startup, so a manifest published via the signed catalog sat dormant until the next service restart (found while shipping the strfry manifest fixes: package.check-updates refreshed the cache but the orchestrator kept rendering the old overlay). - refresh_catalog now reports whether the cached bytes actually changed (write_cache skips identical rewrites), so unchanged hourly polls don't churn the manifest map. - New ContainerOrchestrator::reload_manifests (default no-op); prod delegates to load_manifests — the rebuild is atomic under the state write lock, and the reconciler's durable user-stopped/uninstalled marker filters make a mid-session reload equivalent to the restart path that already runs on every boot. - package.check-updates reloads on change and reports catalog_changed + manifests_reloaded; the hourly update-scheduler tick (and its startup refresh) do the same. Tests: app_catalog 5/5 (new write_cache changed-detection test), reconcile 16/16, knows_app 1/1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2c46da387c
commit
ceb319c292
@@ -172,18 +172,36 @@ impl RpcHandler {
|
||||
|
||||
/// Manual "check for updates": refresh the remote app catalog now. The
|
||||
/// package scanner recomputes each app's `available-update` from the fresh
|
||||
/// catalog on its next cycle and pushes it to the UI. Best-effort — a fetch
|
||||
/// failure leaves the cached catalog in place and reports `refreshed: false`.
|
||||
/// catalog on its next cycle and pushes it to the UI. When the catalog
|
||||
/// bytes changed, the orchestrator's manifest overlay is reloaded in the
|
||||
/// same call so catalog-shipped manifest fixes apply without a service
|
||||
/// restart. Best-effort — a fetch failure leaves the cached catalog in
|
||||
/// place and reports `refreshed: false`.
|
||||
pub(in crate::api::rpc) async fn handle_package_check_updates(
|
||||
&self,
|
||||
_params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
match crate::container::app_catalog::refresh_catalog(&self.config.data_dir).await {
|
||||
Ok(count) => Ok(serde_json::json!({
|
||||
"status": "ok",
|
||||
"refreshed": true,
|
||||
"catalog_apps": count,
|
||||
})),
|
||||
Ok(refresh) => {
|
||||
let mut manifests_reloaded = serde_json::Value::Null;
|
||||
if refresh.changed {
|
||||
if let Some(orch) = &self.orchestrator {
|
||||
match orch.reload_manifests().await {
|
||||
Ok(n) => manifests_reloaded = serde_json::json!(n),
|
||||
Err(e) => tracing::warn!(
|
||||
"check-updates: manifest reload after catalog change failed: {e}"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(serde_json::json!({
|
||||
"status": "ok",
|
||||
"refreshed": true,
|
||||
"catalog_apps": refresh.apps,
|
||||
"catalog_changed": refresh.changed,
|
||||
"manifests_reloaded": manifests_reloaded,
|
||||
}))
|
||||
}
|
||||
Err(e) => Ok(serde_json::json!({
|
||||
"status": "ok",
|
||||
"refreshed": false,
|
||||
|
||||
Reference in New Issue
Block a user