Skip to content

Bound flush() retries so a persistently-retriable upload can't hang teardown#289

Merged
ypopovych merged 2 commits into
mainfrom
fix/flush-bounded-retries
Jul 15, 2026
Merged

Bound flush() retries so a persistently-retriable upload can't hang teardown#289
ypopovych merged 2 commits into
mainfrom
fix/flush-bounded-retries

Conversation

@ypopovych

Copy link
Copy Markdown
Contributor

What

The synchronous flush() on the shutdown path retried a .retry upload result in an unbounded loop. A persistently retriable server (503/500/408/429) or a downed network — both surface as needsRetry — would loop forever, hanging process teardown.

Change

  • Cap flush retries at 3 (1 initial attempt + 3 retries) via maxFlushRetries.
  • On giving up: report failure and leave the undelivered batch on disk for a later run to pick up.
  • The background worker's indefinite cross-tick retry behaviour is unchanged; only the bounded shutdown flush() is affected.

Test

Adds testFlushGivesUpAfterMaxRetriesInsteadOfHanging: a persistently-retriable upload returns failure (not a hang), performs exactly 4 upload attempts, and leaves the batch on disk.

🤖 Generated with Claude Code

…eardown

The synchronous `flush()` on the shutdown path retried a `.retry` upload
result in an unbounded loop. A persistently retriable server (503/500/
408/429) or a downed network — both surface as `needsRetry` — would loop
forever, hanging process teardown.

Cap flush retries at 3 (1 initial attempt + 3 retries). On giving up,
report failure and leave the undelivered batch on disk for a later run.
The background worker's indefinite cross-tick retry behaviour is
unchanged; only the bounded shutdown flush is affected.

Adds a regression test that a persistently-retriable upload returns
failure instead of hanging, attempts exactly 4 uploads, and leaves the
batch on disk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ypopovych ypopovych requested review from a team as code owners July 9, 2026 12:21

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Datadog Autotest: PASS

More details

Retry bounding logic is correct: persistently-retriable uploads now give up after 4 total attempts (1 initial + 3 retries), exit gracefully instead of hanging, and leave the undelivered batch on disk for a later run. Off-by-one semantics, batch preservation, and return value semantics are all sound. No regressions to existing tests.

Was this helpful? React 👍 or 👎

📊 Validated against 4 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit a37f691 · What is Autotest? · Any feedback? Reach out in #autotest

`testFlushGivesUpAfterMaxRetriesInsteadOfHanging` flushed while the worker
was still live, so its scheduled background tick fired right after flush
released the queue and added a stray 5th upload (expected 4, got 5).

Stop the worker before flushing, matching the production shutdown order in
`Feature.stop()` (stop periodic uploads, seal writer, then final flush) so
`flush()` is the only thing uploading the batch. Deterministic 4 uploads.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ypopovych ypopovych merged commit 548f253 into main Jul 15, 2026
11 checks passed
@ypopovych ypopovych deleted the fix/flush-bounded-retries branch July 15, 2026 16:05
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.

2 participants