feat(storage key rot): add admin panel
This commit is contained in:
@@ -76,4 +76,20 @@ pub trait JobHandler: Send + Sync {
|
||||
///
|
||||
/// See trait-level docs for guidance on when to return Ok vs Err.
|
||||
async fn run(&self, args: &JobRunArgs) -> JobOutcome;
|
||||
|
||||
/// `true` iff this handler persists per-run rows to
|
||||
/// `jobs.recoverable_runs` (cursor + findings + resume). Surfaced
|
||||
/// on [`crate::infrastructure::scheduler::registry::JobSummary`]
|
||||
/// so the admin UI can decide whether the row is expandable to
|
||||
/// show a run history + findings drawer, without hardcoding a
|
||||
/// name-based allowlist.
|
||||
///
|
||||
/// Default is `false` — Part 1 periodic handlers (`TrashCleanup`,
|
||||
/// `StorageReconcile`, `GrantCleanup`, `DedupGc`) don't have runs
|
||||
/// or findings. `RecoverableAdapter` overrides to `true` so every
|
||||
/// tenant registered via `register_recoverable_job` flips the flag
|
||||
/// automatically at registration time.
|
||||
fn is_recoverable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,6 +802,14 @@ impl JobHandler for RecoverableAdapter {
|
||||
async fn run(&self, args: &JobRunArgs) -> JobOutcome {
|
||||
run_or_resume(self.inner.clone(), self.provider.clone(), args).await
|
||||
}
|
||||
fn is_recoverable(&self) -> bool {
|
||||
// Every tenant registered through `register_recoverable_job` is
|
||||
// wrapped by this adapter, so this flag flips true for exactly
|
||||
// the set of jobs whose runs + findings the admin UI should
|
||||
// let operators drill into. No name-based allowlists needed
|
||||
// downstream.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Ergonomics: JobRegistry extension for recoverable jobs ─────────────────
|
||||
|
||||
@@ -225,6 +225,7 @@ impl JobRegistry {
|
||||
last_run_at,
|
||||
last_outcome,
|
||||
running: state.current_run_start.is_some(),
|
||||
recoverable: entry.handler.is_recoverable(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -288,6 +289,10 @@ pub enum RegisterError {
|
||||
/// - `running` — true iff the in-flight permit is currently held
|
||||
/// (either the supervisor tick is in progress or an admin trigger
|
||||
/// raced in).
|
||||
/// - `recoverable` — true iff the job persists runs + findings to
|
||||
/// `jobs.recoverable_runs`. Consumed by the admin UI to decide
|
||||
/// whether the row is expandable (drawer with run history +
|
||||
/// findings) and to gate the retention/purge action.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct JobSummary {
|
||||
pub name: String,
|
||||
@@ -300,6 +305,7 @@ pub struct JobSummary {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last_outcome: Option<JobOutcome>,
|
||||
pub running: bool,
|
||||
pub recoverable: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user