Skip to content

feat(sinks): chunk sink deliveries so full-history replays stay under intake limits - #39

Open
Donemmanuelo wants to merge 1 commit into
onelrian:mainfrom
Donemmanuelo:feat/sink-batch-chunking
Open

feat(sinks): chunk sink deliveries so full-history replays stay under intake limits#39
Donemmanuelo wants to merge 1 commit into
onelrian:mainfrom
Donemmanuelo:feat/sink-batch-chunking

Conversation

@Donemmanuelo

Copy link
Copy Markdown

Closes #36.

User-facing impact

A fresh install, lost CURSOR_FILE, or restored old cursor replays the
account's entire audit history in one poll — previously one oversized
request per sink that Loki's push API and many HTTP/SIEM intake endpoints
reject outright, then retry with backoff forever. BATCH_SIZE (default
500, 0 disables) splits each sink's pending batch into chunks, each with
the existing retry/backoff, so a large replay now succeeds in bounded
payloads. The per-sink watermark advances only when every chunk delivers, so
a partial failure retries the whole set next cycle and nothing is skipped.

Verification

  • cargo fmt --check, cargo clippy --all-targets -- -D warnings, and
    cargo test --locked all pass (32 tests, +4 new: chunk splitting, 0
    disables chunking, watermark held on a failed chunk via wiremock
    up_to_n_times, and BATCH_SIZE env parsing/defaulting).
  • docs/CONFIGURATION.md documents the variable and the replay scenario.

Note for the maintainer: docs/SINKS.md in #34 references BATCH_SIZE;
merge this PR before or together with #34 so the reference resolves.

… intake limits (onelrian#36)

A fresh install, lost cursor, or restored old cursor replays the whole
audit history in one poll. BATCH_SIZE (default 500, 0 disables) splits
each sink's pending batch into chunks that each get the existing
retry/backoff; the per-sink watermark advances only when every chunk
delivers, so a partial failure retries the full set next cycle and
nothing is skipped. Documented in CONFIGURATION.md with tests covering
chunk splitting, the 0 = off case, and watermark behavior on a failed
chunk.
Comment thread src/main.rs
};

let mut all_delivered = true;
for chunk in pending.chunks(chunk_size) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chunking by event count doesn't bound bytes - a chunk of 500 events with large meta/user fields can still exceed an intake cap, so the docs' "payloads stay under intake limits" overpromises. Either chunk by estimated encoded size or qualify the claim. Also: the syslog sink opens a fresh TCP connection per send(), so a big replay now costs N connections (one per chunk) instead of one - fine, but worth knowing.

Comment thread docs/CONFIGURATION.md

> [!NOTE]
> A fresh install, a lost cursor, or a restored old cursor delivers the whole
> audit history in one poll. `BATCH_SIZE` splits that replay into

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial-failure semantics worth stating explicitly: if chunk 2 of 3 fails, chunk 1 is already delivered but the watermark stays put, so the next cycle re-sends chunk 1 - real duplicates, and #38's same-timestamp ID tracking does not cover them (they're older than the watermark). At-least-once is fine, just say it: "a partial failure re-delivers the earlier chunks next cycle".

Comment thread src/main.rs
sinks: &[Box<dyn Sink>],
cursors: &mut HashMap<String, Option<DateTime<Utc>>>,
retry_cfg: &RetryConfig,
batch_size: usize,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stacking note: #38 and #39 both change process_cycle and every call site in tests.rs - they'll conflict on merge; the combined behavior is coherent but pick an order (#38 then #39, or stack them). Also, no CI is reported on this fork branch - ensure the test gate runs before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: chunk sink batches to survive full-history replay

2 participants