Skip to content

fix(shutdown): handle runtimeDone without metrics; wait for the processor before the final flush - #1457

Closed
DarcyRaynerDD wants to merge 3 commits into
darcy.rayner/shutdown-telemetry-drainfrom
darcy.rayner/shutdown-reason-fallback
Closed

DarcyRaynerDD wants to merge 3 commits into
darcy.rayner/shutdown-telemetry-drainfrom
darcy.rayner/shutdown-reason-fallback

Conversation

@DarcyRaynerDD

@DarcyRaynerDD DarcyRaynerDD commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Overview

Two small shutdown hardening changes on top of #1455.

  • platform.runtimeDone without metrics is no longer dropped. It was matched only as metrics: Some(..), but AWS marks metrics optional, so such an event fell through to "Unforwarded Telemetry event".
    • That lost its error, timeout and OOM counts.
    • In End mode it also stalled the flush loop, which waits on runtimeDone before calling /next.
    • The event is now counted from status. Span processing is skipped, because without a duration the invocation span would be sent with zero length. runtime_done_received stays false, so reparenting won't send it either.
  • Shutdown waits for the invocation processor before the final flush. A new Barrier command resolves once the processor has handled every earlier command. That includes the fire-and-forget OnShutdownEvent (shutdown and unused-init metrics, the held-back cold-start invocation count) and OnOutOfMemoryError. Before, nothing guaranteed these were applied before flush_blocking_final.

What changed since this PR was opened. It first also counted errors and timeouts from the SHUTDOWN reason (TIMEOUT or FAILURE) when the in-flight invocation's runtimeDone hadn't arrived. The failure-accounting suite showed that overcounting on every attempt:

Attempt Default strategy errors (expected 12) Default strategy timeouts (expected 6) end control
1 16 6 exact
2 17 7 exact
3 15 6 exact

#1455 alone was exact on the same suite. A runtimeDone that the closing listener refuses is redelivered to the restarted extension, which counts it, so the SHUTDOWN-reason count was a second count. It has been removed.

Stacked on #1455.

Testing

  • New unit test: a runtimeDone without metrics counts one error and one timeout, sends no span, and isn't marked ready for reparenting.
  • Existing test extended: the no-op processor test now covers the new Barrier command.
  • Not unit-tested: the main.rs match-arm change.
  • Existing checks: cargo test --workspace, cargo clippy and cargo fmt pass.
  • Integration (pending): the failure-accounting suite runs on this branch and should be exact on every attempt, as on fix(shutdown): send Tombstone after telemetry is drained #1455.

🤖 Generated with Claude Code

…rived

After the shutdown drain, send the processor the SHUTDOWN reason. For a TIMEOUT
or FAILURE shutdown in On-Demand mode, if the last invoked request never got a
platform.runtimeDone, count its error (and timeout), and mark it so a runtimeDone
can't count it again. Awaiting the processor's reply also guarantees the earlier
fire-and-forget shutdown and OOM commands are handled before the final flush.

Also handle platform.runtimeDone events without a metrics field instead of
dropping them, which lost their error counts and stalled End-mode flushing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DarcyRaynerDD
DarcyRaynerDD requested a review from a team as a code owner October 23, 2026 18:40
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T20:30:02.587223Z 44afb59 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 251e7180b9

ℹ️ 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".

Comment on lines +627 to +628
if let Some(context) = self.context_buffer.get_mut(request_id) {
context.runtime_done_received = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid marking metricless spans ready for reparenting

When a tracer is active and update_reparenting runs after this metricless runtimeDone, runtime_done_received satisfies its send-readiness condition, so the trace agent returns this context to send_ctx_spans and emits the invocation span even though its runtime duration was never populated. This defeats the intended zero-length-span guard for that event ordering; tracking receipt separately from span readiness, or otherwise excluding this context from reparenting sends, would prevent it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, thanks. 7af598c moved the counting state off runtime_done_received so it no longer marked spans ready for reparenting. Since then, 44afb59 removed the SHUTDOWN-reason count entirely, because the integration suite showed it double counting. A metricless runtimeDone still leaves runtime_done_received false, and the test asserts that, so reparenting won't send that span.

@datadog-official

datadog-official Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Pipelines

✨ Unblock PR with BitsAI

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 1 Pipeline job failed

DataDog/datadog-lambda-extension | e2e-test-status (amd64) — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 44afb59 | Docs | View more details | Give us feedback!

@DarcyRaynerDD
DarcyRaynerDD added this pull request to stack #1456 October 23, 2026 20:05
DarcyRaynerDD and others added 2 commits October 23, 2026 16:11
runtime_done_received also marks the invocation span ready to send during reparenting, so setting it when counting from the SHUTDOWN reason or a metricless runtimeDone could send an unfinished span. Track the uncounted invocation on the processor instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 20:26
@DarcyRaynerDD DarcyRaynerDD changed the title fix(shutdown): count timeouts and failures whose runtimeDone never arrived fix(shutdown): handle runtimeDone without metrics; wait for the processor before the final flush Oct 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The timing-sensitive shutdown changes need the pending failure-accounting integration results reviewed before approval.

No open issues 🎉

What changed in this PR

Hardens shutdown handling on top of #1455 so the Lambda extension processes runtime completion events without metrics and waits for queued invocation-processor work before the final flush.

Changes:

  • Counts failures from runtimeDone status even when metrics are absent, while skipping span processing without a duration.
  • Adds a processor barrier and awaits it during shutdown before the final flush.
  • Adds optional-metrics regression coverage and extends the no-op processor test to cover the barrier.
File Description
bottlecap/​src/​lifecycle/​invocation/​processor.rs Handles optional runtime metrics and tests timeout counting without emitting a span.
bottlecap/​src/​lifecycle/​invocation/​processor_service.rs Passes optional metrics through the service and adds the barrier command.
bottlecap/​src/​bin/​bottlecap/​main.rs Forwards runtime completion events without metrics and awaits the shutdown barrier.

Review effort: Balanced

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44afb591b5

ℹ️ 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".

Comment on lines +621 to +623
let Some(metrics) = metrics else {
return;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve end-event pairing before returning

When an On-Demand tracer omits the request-ID header and its UniversalInstrumentationEnd is already buffered, a metricless runtimeDone returns here before pair_platform_runtime_done_event can consume that event. If the environment remains warm (for example, a successful runtimeDone whose optional metrics are absent), the next metric-bearing invocation consumes the stale response and associates its metadata/status with the wrong context, leaving the FIFO pairing permanently one invocation behind. Retire the buffered end event—or otherwise advance the pairing state—before skipping span completion.

Useful? React with 👍 / 👎.

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