summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-20 01:32:12 +0200
committertv <tv@krebsco.de>2026-10-20 01:32:12 +0200
commit31dddb08e4f36392ed9b033f78efd00c243c46bb (patch)
tree582d63b3ff6c35c9cee2babb63504f04df8c2105
parent89407b7c6625f65813ac70e11ed77a487245d17b (diff)
add force param to POST /admin/compaction
-rw-r--r--src/compaction/api.rs26
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,