Skip to content

[SVLS-8230] Fix SnapStart cold_start tag using restore_time#1139

Merged
jchrostek-dd merged 1 commit into
mainfrom
john/svls-8230
Apr 8, 2026
Merged

[SVLS-8230] Fix SnapStart cold_start tag using restore_time#1139
jchrostek-dd merged 1 commit into
mainfrom
john/svls-8230

Conversation

@jchrostek-dd

@jchrostek-dd jchrostek-dd commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

SnapStart restore invocations were being misclassified as proactive_initialization=true, cold_start=false. The root cause is in set_init_tags(): it uses sandbox_init_time (captured at snapshot creation) to measure how long ago the sandbox was initialized. For SnapStart, this gap is always large (snapshot creation vs. restore), so the >10s threshold is always exceeded.

Fix: Add a restore_time field to Processor, set from the existing PlatformRestoreStart telemetry event. For SnapStart functions, set_init_tags() now measures time since the restore — not since snapshot creation.

Changes

  • bottlecap/src/config/aws.rs — Added is_snapstart() method (mirrors is_managed_instance_mode() pattern)
  • bottlecap/src/lifecycle/invocation/processor.rs — Added restore_time: Option<Instant>, set in on_platform_restore_start(), used in set_init_tags() for SnapStart-aware cold start detection
  • integration-tests/tests/snapstart.test.ts — Added cold_start=true assertion for restore invocations and cold_start=false for warm invocations (Java + .NET, 2 threads × 2 invocations each with 5s delay)

Scope

  • Java + .NET only — Python SnapStart requires a tracer-level fix (separate ticket: SVLS-5988)
  • Node.js — AWS does not support SnapStart for Node.js

Tests

Integration test suite: integration-tests/tests/snapstart.test.ts

Assertions added:

  • Restore invocations: cold_start=true, init_type=snap-start, snapstart_restore span present, no cold_start span
  • Warm invocations: cold_start=false, init_type=snap-start, no snapstart_restore span
  • Trace isolation: all 4 invocations have unique trace IDs

Jira

SVLS-8230

@jchrostek-dd
jchrostek-dd force-pushed the john/svls-8230 branch 3 times, most recently from 415f7e7 to 1a7ce63 Compare April 8, 2026 14:31
@jchrostek-dd
jchrostek-dd marked this pull request as ready for review April 8, 2026 15:02
@jchrostek-dd
jchrostek-dd requested a review from a team as a code owner April 8, 2026 15:02
@jchrostek-dd
jchrostek-dd requested review from Copilot and lym953 April 8, 2026 15:02

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.

Pull request overview

This PR fixes a bug in SnapStart cold_start tag detection by using restore_time instead of sandbox_init_time to measure the time since the restore event for cold_start classification. Previously, SnapStart restore invocations were misclassified as proactive_initialization=true, cold_start=false.

Changes:

  • Added is_snapstart() method to AwsConfig to check if the function uses SnapStart initialization
  • Added restore_time: Option<Instant> field to Processor that tracks when the SnapStart restore event occurs
  • Modified cold_start detection logic in set_init_tags() to measure time since restore for SnapStart functions instead of time since sandbox initialization
  • Added integration test assertions for SnapStart cold_start tag values for both restore and warm invocations

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
bottlecap/src/config/aws.rs Added is_snapstart() method to detect SnapStart functions
bottlecap/src/lifecycle/invocation/processor.rs Added restore_time tracking and SnapStart-aware cold start detection logic
integration-tests/tests/snapstart.test.ts Added assertions for correct cold_start tag values on restore and warm invocations

Comment on lines +258 to +276
if self.aws_config.is_snapstart() {
match self.restore_time {
None => {
// PlatformRestoreStart hasn't arrived yet — restore and invoke
// happened close together, so this is a cold start (not proactive).
cold_start = true;
}
Some(restore_time) => {
let now = Instant::now();
let time_since_restore = now.duration_since(restore_time);
if time_since_restore.as_millis()
> PROACTIVE_INITIALIZATION_THRESHOLD_MS.into()
{
proactive_initialization = true;
} else {
cold_start = true;
}
}
}

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

The SnapStart cold_start detection logic incorrectly tags warm invocations as cold starts. On the first SnapStart invocation, restore_time is set and time since restore is near 0ms, correctly setting cold_start=true. However, on subsequent warm invocations on the same container (which reuse the same restore_time value), the time since restore keeps increasing. For warm invocations that occur within 10 seconds of the restore, this causes them to incorrectly have cold_start=true instead of cold_start=false.

The issue is that restore_time should be cleared or the logic should distinguish between the first invocation and subsequent warm invocations. Consider checking if this is the first time set_init_tags() is being called using a flag or by detecting context transitions.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is inaccurate since we first check 'context_buffer.is_empty()'

@@ -252,12 +255,35 @@ impl Processor {

// If it's empty, then we are in a cold start

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.

Outdated comment

let now = Instant::now();
let time_since_restore = now.duration_since(restore_time);
if time_since_restore.as_millis()
> PROACTIVE_INITIALIZATION_THRESHOLD_MS.into()

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.

What does this const mean? Where does the value come from? Can we add some comment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a comment to PROACTIVE_INITIALIZATION_THRESHOLD_MS.

SnapStart restore invocations were misclassified as proactive_initialization
because sandbox_init_time (from snapshot creation) always exceeded the 10s
threshold. Fix by tracking restore_time from PlatformRestoreStart telemetry
and using it for proactive init detection in SnapStart functions.

When restore_time is None (telemetry not yet delivered), assume cold start
since the restore and invoke happened close together.

https://datadoghq.atlassian.net/browse/SVLS-8230
@jchrostek-dd
jchrostek-dd merged commit 1470194 into main Apr 8, 2026
52 checks passed
@jchrostek-dd
jchrostek-dd deleted the john/svls-8230 branch April 8, 2026 17:04
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.

3 participants