From 5638641ee4165b6250c99d7e809da49f3a062bce Mon Sep 17 00:00:00 2001 From: dawn <90008@klbr.net> Date: Tue, 29 Sep 2026 19:33:30 +0300 Subject: [PATCH] [debug] cap /debug/seed_events at 10k events like its sibling a seed is one sequenced commit, so an uncapped count held the sequencer lock, and every writer behind it, for as long as it took to stage. --- src/api/debug.rs | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/api/debug.rs b/src/api/debug.rs index b51b4f7..fe339ac 100644 --- a/src/api/debug.rs +++ b/src/api/debug.rs @@ -462,6 +462,19 @@ pub async fn handle_debug_seed_watermark( Ok(StatusCode::OK) } +/// the most events one seed request writes. a seed is one sequenced commit, +/// which holds up every other writer until it lands. +#[cfg(any(feature = "indexer_stream", feature = "relay"))] +const MAX_SEEDED_EVENTS: usize = 10_000; + +#[cfg(any(feature = "indexer_stream", feature = "relay"))] +fn seed_count(count: u64) -> Result { + usize::try_from(count) + .ok() + .filter(|count| *count <= MAX_SEEDED_EVENTS) + .ok_or(StatusCode::BAD_REQUEST) +} + #[derive(Deserialize)] #[cfg(any(feature = "indexer_stream", feature = "relay"))] pub struct DebugSeedEventsRequest { @@ -477,6 +490,7 @@ pub async fn handle_debug_seed_events( if req.partition != "events" && req.partition != "relay_events" { return Err(StatusCode::BAD_REQUEST); } + let count = seed_count(req.count)?; state .db @@ -484,12 +498,12 @@ pub async fn handle_debug_seed_events( let mut txn = crate::db::Txn::new(db); if req.partition == "events" { #[cfg(feature = "indexer_stream")] - for _ in 0..req.count { + for _ in 0..count { txn.outbox.stream.push_record(b"dummy".to_vec(), None); } } else if req.partition == "relay_events" { #[cfg(feature = "relay")] - for _ in 0..req.count { + for _ in 0..count { txn.outbox .relay .push_fixture(bytes::Bytes::from_static(b"dummy")); @@ -514,10 +528,7 @@ pub async fn handle_debug_seed_relay_jetstream_commits( State(state): State>, Query(req): Query, ) -> Result { - let count = usize::try_from(req.count) - .ok() - .filter(|count| *count <= 10_000) - .ok_or(StatusCode::BAD_REQUEST)?; + let count = seed_count(req.count)?; state .db .run(move |db| { @@ -751,3 +762,16 @@ pub async fn handle_debug_seed_backlinks( StatusCode::INTERNAL_SERVER_ERROR }) } + +#[cfg(all(test, any(feature = "indexer_stream", feature = "relay")))] +mod tests { + use super::*; + + #[test] + fn seeds_are_capped() { + assert_eq!(seed_count(0), Ok(0)); + assert_eq!(seed_count(10_000), Ok(10_000)); + assert_eq!(seed_count(10_001), Err(StatusCode::BAD_REQUEST)); + assert_eq!(seed_count(u64::MAX), Err(StatusCode::BAD_REQUEST)); + } +} -- 2.51.2