diff options
| author | tv <tv@krebsco.de> | 2026-10-20 01:32:12 +0200 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-20 01:32:12 +0200 |
| commit | 31dddb08e4f36392ed9b033f78efd00c243c46bb (patch) | |
| tree | 582d63b3ff6c35c9cee2babb63504f04df8c2105 | |
| parent | 89407b7c6625f65813ac70e11ed77a487245d17b (diff) | |
add force param to POST /admin/compaction
| -rw-r--r-- | src/compaction/api.rs | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/src/compaction/api.rs b/src/compaction/api.rs index a2fde13..9a77e4d 100644 --- a/src/compaction/api.rs +++ b/src/compaction/api.rs @@ -2,7 +2,8 @@ //! //! * `POST /admin/compaction` proposes a compaction of the current epoch. The receiving //! node becomes its coordinator. `202` with the report, or with `?wait=true` the final -//! report once decided. A dropped request does not abort anything. +//! report once decided. A dropped request does not abort anything. `?force=true` +//! accepts a `settleSecs` below the dormancy threshold (tests, single-site clusters). //! * `GET /admin/compactions` lists all compactions. //! * `GET /admin/compactions/{id}` reports one; `?wait=true` long-polls until decided //! (bounded by the proposal's own expiry). @@ -29,7 +30,7 @@ use axum::{ use serde::{Deserialize, Serialize}; use serde_json::{json, Value as JsonValue}; use tokio::sync::broadcast; -use tracing::{error, info}; +use tracing::{error, info, warn}; use uuid::Uuid; use super::coordinator; @@ -47,6 +48,15 @@ pub(crate) struct WaitQuery { } #[derive(Debug, Default, Deserialize)] +pub(crate) struct StartQuery { + #[serde(default)] + wait: bool, + /// Allows a settle period shorter than the dormancy threshold. + #[serde(default)] + force: bool, +} + +#[derive(Debug, Default, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct StartRequest { replay_window: Option<Retention>, @@ -128,7 +138,7 @@ async fn wait_until_final<H: Host>(host: &H, id: &str) -> Option<Report> { pub(crate) async fn start<H: Host>( State(host): State<H>, - Query(query): Query<WaitQuery>, + Query(query): Query<StartQuery>, body: Bytes, ) -> Response { if !host.is_node_ready().await { @@ -155,11 +165,17 @@ pub(crate) async fn start<H: Host>( .settle_secs .map(Duration::from_secs) .unwrap_or(dormant_after * 2); - if settle < dormant_after { + if settle < dormant_after && query.force { + warn!( + settle_secs = settle.as_secs_f64(), + dormant_after_secs = dormant_after.as_secs(), + "Forced settle period shorter than the dormancy threshold; a partition may go unnoticed" + ); + } else if settle < dormant_after { return error_response( StatusCode::BAD_REQUEST, format!( - "settleSecs must be at least {} (the dormancy threshold), so a partition is detected before deciding", + "settleSecs must be at least {} (the dormancy threshold), so a partition is detected before deciding; add ?force=true to override", dormant_after.as_secs() ), None, |
