scheduled prompts: fire-now operator + manager surfaces (closes #467)

This commit is contained in:
damocles 2026-05-26 13:43:04 +02:00 committed by Mara
commit 3cd9240594
6 changed files with 251 additions and 1 deletions

View file

@ -76,6 +76,7 @@ pub async fn serve(port: u16, coord: Arc<Coordinator>) -> Result<()> {
.route("/meta-update", post(post_meta_update))
.route("/api/schedules", get(api_schedules).post(post_schedule_new))
.route("/api/schedules/{id}/cancel", post(post_schedule_cancel))
.route("/api/schedules/{id}/fire-now", post(post_schedule_fire_now))
.route("/dashboard/stream", get(dashboard_stream))
.route("/dashboard/history", get(dashboard_history))
// Anything not matched by the dynamic routes above falls
@ -1440,6 +1441,24 @@ async fn post_schedule_new(
}
}
/// `POST /api/schedules/{id}/fire-now` — operator-initiated
/// out-of-band fire of a scheduled prompt (#467). Runs the
/// per-target fan-out once immediately and reports per-target
/// outcome counts. Does NOT touch `next_fire_at_unix` on
/// recurring schedules (their cadence stays intact); one-shot
/// schedules are consumed (cancelled) by a manual fire — the
/// operator's intent is "send this now, the scheduled time was
/// wrong."
async fn post_schedule_fire_now(
State(state): State<AppState>,
AxumPath(id): AxumPath<i64>,
) -> Response {
match crate::scheduled_prompts_worker::fire_now(&state.coord, id).await {
Ok(report) => axum::Json(report).into_response(),
Err(e) => error_response(&format!("fire schedule {id} now: {e:#}")),
}
}
#[derive(serde::Deserialize, Default)]
struct CancelScheduleForm {
/// `None` / absent / empty array → cancel whole schedule.