@@ -49,6 +49,11 @@ use crate::{
4949pub const MS_TO_NS : f64 = 1_000_000.0 ;
5050pub const S_TO_MS : u64 = 1_000 ;
5151pub const S_TO_NS : f64 = 1_000_000_000.0 ;
52+ /// Threshold for classifying a Lambda cold start as proactive initialization.
53+ ///
54+ /// Proactive initialization is a Lambda optimization where the runtime pre-initializes
55+ /// a sandbox before any invocation is scheduled, to reduce cold start latency for future
56+ /// requests.
5257pub const PROACTIVE_INITIALIZATION_THRESHOLD_MS : u64 = 10_000 ;
5358
5459pub const DATADOG_INVOCATION_ERROR_MESSAGE_KEY : & str = "x-datadog-invocation-error-msg" ;
@@ -96,6 +101,8 @@ pub struct Processor {
96101 /// logs agent. Decouples the trace agent from the logs agent: the trace agent sends spans
97102 /// to the lifecycle processor, which extracts durable context and relays it here.
98103 durable_context_tx : mpsc:: Sender < DurableContextUpdate > ,
104+ /// Time of the `SnapStart` restore event, set when `PlatformRestoreStart` is received.
105+ restore_time : Option < Instant > ,
99106}
100107
101108impl Processor {
@@ -137,6 +144,7 @@ impl Processor {
137144 active_invocations : 0 ,
138145 awaiting_first_invocation : false ,
139146 durable_context_tx,
147+ restore_time : None ,
140148 }
141149 }
142150
@@ -252,12 +260,35 @@ impl Processor {
252260
253261 // If it's empty, then we are in a cold start
254262 if self . context_buffer . is_empty ( ) {
255- let now = Instant :: now ( ) ;
256- let time_since_sandbox_init = now. duration_since ( self . aws_config . sandbox_init_time ) ;
257- if time_since_sandbox_init. as_millis ( ) > PROACTIVE_INITIALIZATION_THRESHOLD_MS . into ( ) {
258- proactive_initialization = true ;
263+ if self . aws_config . is_snapstart ( ) {
264+ match self . restore_time {
265+ None => {
266+ // PlatformRestoreStart hasn't arrived yet — restore and invoke
267+ // happened close together, so this is a cold start (not proactive).
268+ cold_start = true ;
269+ }
270+ Some ( restore_time) => {
271+ let now = Instant :: now ( ) ;
272+ let time_since_restore = now. duration_since ( restore_time) ;
273+ if time_since_restore. as_millis ( )
274+ > PROACTIVE_INITIALIZATION_THRESHOLD_MS . into ( )
275+ {
276+ proactive_initialization = true ;
277+ } else {
278+ cold_start = true ;
279+ }
280+ }
281+ }
259282 } else {
260- cold_start = true ;
283+ let now = Instant :: now ( ) ;
284+ let time_since_sandbox_init = now. duration_since ( self . aws_config . sandbox_init_time ) ;
285+ if time_since_sandbox_init. as_millis ( )
286+ > PROACTIVE_INITIALIZATION_THRESHOLD_MS . into ( )
287+ {
288+ proactive_initialization = true ;
289+ } else {
290+ cold_start = true ;
291+ }
261292 }
262293
263294 // Resolve runtime only once
@@ -383,6 +414,8 @@ impl Processor {
383414 /// This is used to create a `snapstart_restore` span, since this telemetry event does not
384415 /// provide a `request_id`, we try to guess which invocation is the restore similar to init.
385416 pub fn on_platform_restore_start ( & mut self , time : DateTime < Utc > ) {
417+ self . restore_time = Some ( Instant :: now ( ) ) ;
418+
386419 let start_time: i64 = SystemTime :: from ( time)
387420 . duration_since ( UNIX_EPOCH )
388421 . expect ( "time went backwards" )
0 commit comments