Repository navigation
fix(shutdown): send Tombstone after telemetry is drained - #1455
DarcyRaynerDD wants to merge 3 commits into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3390ac2c03
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| let deadline = tokio::time::Instant::now() + DRAIN_TIMEOUT; | ||
| loop { | ||
| match tokio::time::timeout_at(deadline, self.rx.recv()).await { |
There was a problem hiding this comment.
Drain queued telemetry before honoring the deadline
When shutdown finds a large telemetry backlog or processing takes more than 250 ms, this fixed absolute deadline expires while events can still be queued in self.rx; the next timeout_at then returns Err, the agent sends the Tombstone, and the main loop proceeds to its final flush while the remaining logs and lifecycle events are dropped. Apply the timeout only while waiting for the listener to disconnect or for another event, while always draining already-queued events before emitting the Tombstone.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
I don't think this can happen with tokio 1.50:
Timeout::pollpolls the inner future before the timer (time/timeout.rs:199-206), andReceiver::recvreturnsReadyfor every buffered message (sync/mpsc/chan.rs:302-306). An expired deadline therefore can't win while events are queued. The loop keeps draining past the deadline and only hitsErronce the queue is empty.- Budget exhaustion doesn't change that.
recvonly returnsPendingfor budget when the budget is already zero before the call (chan.rs:295). In that casepoll_delaypolls theSleepunder the same budget (sleep.rs:430), so the task yields and resumes rather than timing out.
beb8006 adds test_queued_events_forwarded_after_drain_timeout. It queues enough forwarded events to fill the event bus past the deadline, then 500 function logs (which don't yield), then a runtimeDone, and asserts that every forwarded event reaches the bus before the Tombstone. It passes without any change to the drain loop. I also checked multi-thread runtimes with concurrent senders and 200k-event backlogs, and nothing was dropped.
The remaining gap is a send that has claimed a slot but not finished writing it at the exact moment of the deadline. That's microseconds wide and equivalent to an event arriving just after the 250 ms cap, which is the intended tradeoff. Bounding the shutdown sequence as a whole against Lambda's deadline is a planned follow-up.
At shutdown the Telemetry API listener pushed the Tombstone straight onto the event bus, while telemetry events still had to pass through the logs agent. The main loop stops reading at the first Tombstone, so a platform.runtimeDone, platform.report or OOM log line still in the logs agent was dropped. For an invocation that timed out or crashed, that lost its errors/timeouts/OOM enhanced metrics. The logs agent now sends the Tombstone after its channel disconnects (the listener has shut down and dropped its sender) or a 250ms drain timeout elapses. This also replaces the busy-spin drain with an awaited recv. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…utdown The logs agent's shutdown drain can now time out and drop its receiver while a Telemetry API request is still in flight. Return 503 instead of panicking, which aborts the process in release builds. Also correct the Managed Instance shutdown comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re-accounting suite Events still queued when the logs agent's shutdown drain deadline passes are forwarded before the Tombstone, because timeout_at polls recv first. Add a test that pins this down. Register the failure-accounting integration suite now that the fix is in place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3390ac2 to
beb8006
Compare
❌ ErrorsYour PR has failed checks. Please review the issues below and take necessary action before merging. 🚦 1 Pipeline job failed
Useful? React with 👍 / 👎 This comment will be updated automatically if new data arrives.🔗 Commit SHA: beb8006 | Docs | View more details | Give us feedback! |
The failure-accounting suite showed the count double counting: errors were 3-5 over on the default-strategy function in every attempt, while #1455 alone was exact. A runtimeDone that the closing listener refuses is redelivered to the restarted extension, which counts it, so counting it again from the SHUTDOWN reason was wrong. Keep the rest: platform.runtimeDone without metrics is still counted (without sending a zero-length span), and shutdown now waits on a processor barrier so earlier fire-and-forget commands are handled before the final flush. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@DataDog review |
There was a problem hiding this comment.
More details
The logs agent places the Tombstone after drained telemetry, allowing the main loop to process shutdown events before stopping. The completed static review found no actionable regression.
🤖 Bits Code Review · Commit beb8006
Overview
Fixes undercounted
aws.lambda.enhanced.errors,timeoutsandout_of_memorywhen a function times out, crashes or OOMs after the extension has switched to periodic or continuous flushing.Cause. At shutdown, the Telemetry API listener pushed the Tombstone (the "all events processed" marker) straight onto the event bus. Telemetry events take a longer path: listener → logs agent → event bus. The main loop stops reading at the first Tombstone. So a
platform.runtimeDone,platform.reportor OOM log line for the failing invocation that was still in the logs agent got dropped. That lost the invocation's errors, timeouts, OOM, duration and memory metrics, its timeout span, and its last log lines. End mode was protected for the counts, because it waits forruntimeDonebefore calling/next. This is a regression: #886 drained the bus until it closed, and #947 replaced that with a wait that stops at the first Tombstone.Changes:
recvunder the timeout.panic = "abort").failure-accountingintegration suite from test(integration): add failure-accounting suite for timeout/crash enhanced metrics #1454 is registered in the CI matrix, so it becomes blocking together with this fix.Implications:
Stacked on #1454, which adds the
failure-accountingintegration suite that reproduces the loss onmain.Testing
cargo test --workspace,cargo clippyandcargo fmtpass.failure-accountingsuite runs on this branch with 12 resets per run. The Default-strategy function should match exactly on every attempt. Please check all attempts, sinceretry: 2can hide a failed one.🤖 Generated with Claude Code