feat(stateful-templates): materialize cron+queue templates + hooks (M5.2-M5.4)
materialize::rematerialize_stateful_templates reconciles a group cron/queue template into one app-owned copy per descendant (materialized_from = template), via the all-apps app_chain CTE ⋈ group-owned stateful templates. A precise create/delete diff preserves cron last_fired_at on unchanged copies; a queue copy is skipped-with-warning when the app already fills that queue's consumer slot (the one-consumer invariant). Called full-live at the route-rebuild chokepoints: apply (single + tree), app create/delete (apps_api), group reparent (groups_api) — AppsState/GroupsState gain a pool. Pinned by tests/stateful_templates.rs (per-app copy, idempotent, new-app materializes, reparent de-materializes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,10 @@ pub struct AppsState {
|
||||
/// Group tree — resolves an app's parent group at create time
|
||||
/// (defaults to the instance root).
|
||||
pub groups: Arc<dyn GroupRepository>,
|
||||
/// §4.5 M5: creating/deleting an app changes which ancestor-group stateful
|
||||
/// templates it inherits, so its materialized cron/queue copies are
|
||||
/// reconciled here (full-live, mirroring the route_table rebuild).
|
||||
pub pool: sqlx::PgPool,
|
||||
}
|
||||
|
||||
pub fn apps_router(state: AppsState) -> Router {
|
||||
@@ -565,6 +569,11 @@ async fn refresh_route_cache(state: &AppsState) {
|
||||
{
|
||||
tracing::warn!(error = %e, "apps: route table refresh failed; it will self-heal");
|
||||
}
|
||||
// §4.5 M5: reconcile materialized stateful-template copies for the changed
|
||||
// app set (best-effort; self-heals on the next mutation).
|
||||
if let Err(e) = crate::materialize::rematerialize_stateful_templates(&state.pool).await {
|
||||
tracing::warn!(error = %e, "apps: stateful-template materialization failed; it will self-heal");
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh_domain_cache(state: &AppsState) -> Result<(), AppsApiError> {
|
||||
|
||||
Reference in New Issue
Block a user