From 72d31d24eec0a198451e04c8cf67c08cf8528ba5 Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Fri, 11 Jul 2025 16:36:16 -0400 Subject: [PATCH 1/5] chore: Add doc and rename function for flushing strategy --- bottlecap/src/config/flush_strategy.rs | 29 ++++++++++++++ bottlecap/src/config/mod.rs | 1 + bottlecap/src/lifecycle/flush_control.rs | 27 ++++++------- bottlecap/src/lifecycle/invocation_times.rs | 44 ++++++++++++--------- 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/bottlecap/src/config/flush_strategy.rs b/bottlecap/src/config/flush_strategy.rs index a72a24161..e73795d1c 100644 --- a/bottlecap/src/config/flush_strategy.rs +++ b/bottlecap/src/config/flush_strategy.rs @@ -8,13 +8,42 @@ pub struct PeriodicStrategy { #[derive(Clone, Copy, Debug, PartialEq)] pub enum FlushStrategy { + // Flush every 1s and at the end of the invocation Default, + // User specifies the interval in milliseconds, will not block on the runtimeDone event + Periodically(PeriodicStrategy), + // Always flush at the end of the invocation End, + // Flush both (1) at the end of the invocation and (2) periodically with the specified interval EndPeriodically(PeriodicStrategy), + // Flush in a non-blocking, asynchronous manner, so the next invocation can start without waiting + // for the flush to complete + Continuously(PeriodicStrategy), +} + +// A restricted subset of `FlushStrategy`. The Default strategy is now allowed, which is required to be +// translated into a concrete strategy. +#[allow(clippy::module_name_repetitions)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ConcreteFlushStrategy { Periodically(PeriodicStrategy), + End, + EndPeriodically(PeriodicStrategy), Continuously(PeriodicStrategy), } +impl From for ConcreteFlushStrategy { + fn from(strategy: FlushStrategy) -> ConcreteFlushStrategy { + match strategy { + FlushStrategy::Periodically(p) => ConcreteFlushStrategy::Periodically(p), + FlushStrategy::End => ConcreteFlushStrategy::End, + FlushStrategy::Continuously(p) => ConcreteFlushStrategy::Continuously(p), + FlushStrategy::EndPeriodically(p) => ConcreteFlushStrategy::EndPeriodically(p), + FlushStrategy::Default => unreachable!("Default strategy is not allowed"), + } + } +} + // Deserialize for FlushStrategy // Flush Strategy can be either "end", "end,", or "periodically," impl<'de> Deserialize<'de> for FlushStrategy { diff --git a/bottlecap/src/config/mod.rs b/bottlecap/src/config/mod.rs index e1e2f7f1e..8cbc32842 100644 --- a/bottlecap/src/config/mod.rs +++ b/bottlecap/src/config/mod.rs @@ -240,6 +240,7 @@ pub struct Config { pub api_key: String, pub log_level: LogLevel, + // Timeout for the request to flush data to Datadog endpoint pub flush_timeout: u64, // Proxy diff --git a/bottlecap/src/lifecycle/flush_control.rs b/bottlecap/src/lifecycle/flush_control.rs index 1d60594b7..2365c2717 100644 --- a/bottlecap/src/lifecycle/flush_control.rs +++ b/bottlecap/src/lifecycle/flush_control.rs @@ -1,4 +1,4 @@ -use crate::config::flush_strategy::FlushStrategy; +use crate::config::flush_strategy::{ConcreteFlushStrategy, FlushStrategy}; use std::time; use tokio::time::{Interval, MissedTickBehavior::Skip}; @@ -15,6 +15,7 @@ pub struct FlushControl { flush_timeout: u64, } +// The flush behavior for the current moment #[derive(Copy, Clone, Debug, PartialEq)] pub enum FlushDecision { Continuous, @@ -23,12 +24,6 @@ pub enum FlushDecision { Dont, } -// 1. Default Strategy -// - Flush every 1s and at the end of the invocation -// 2. Periodic Strategy -// - User specifies the interval in milliseconds, will not block on the runtimeDone event -// 3. End strategy -// - Always flush at the end of the invocation impl FlushControl { #[must_use] pub fn new(flush_strategy: FlushStrategy, flush_timeout: u64) -> FlushControl { @@ -57,12 +52,15 @@ impl FlushControl { i.set_missed_tick_behavior(Skip); i } + // TODO: Why is this 15 minutes? FlushStrategy::End => { tokio::time::interval(tokio::time::Duration::from_millis(FIFTEEN_MINUTES)) } } } + // Evaluate the flush decision for the current moment, based on the flush strategy, current time, + // and the past invocation times. #[must_use] pub fn evaluate_flush_decision(&mut self) -> FlushDecision { let now = time::SystemTime::now() @@ -71,16 +69,13 @@ impl FlushControl { .as_secs(); self.invocation_times.add(now); let evaluated_flush_strategy = if self.flush_strategy == FlushStrategy::Default { - &self.invocation_times.should_adapt(now, self.flush_timeout) + &self.invocation_times.evaluate_default_strategy(now, self.flush_timeout) } else { // User specified one - &self.flush_strategy + &self.flush_strategy.into() }; match evaluated_flush_strategy { - FlushStrategy::Default => { - unreachable!("should_adapt must translate default strategy to concrete strategy") - } - FlushStrategy::Periodically(strategy) => { + ConcreteFlushStrategy::Periodically(strategy) => { if self.interval_passed(now, strategy.interval) { self.last_flush = now; // TODO calculate periodic rate. if it's more frequent than the flush_timeout @@ -90,7 +85,7 @@ impl FlushControl { FlushDecision::Dont } } - FlushStrategy::Continuously(strategy) => { + ConcreteFlushStrategy::Continuously(strategy) => { if self.interval_passed(now, strategy.interval) { self.last_flush = now; // TODO calculate periodic rate. if it's more frequent than the flush_timeout @@ -100,8 +95,8 @@ impl FlushControl { FlushDecision::Dont } } - FlushStrategy::End => FlushDecision::End, - FlushStrategy::EndPeriodically(strategy) => { + ConcreteFlushStrategy::End => FlushDecision::End, + ConcreteFlushStrategy::EndPeriodically(strategy) => { if self.interval_passed(now, strategy.interval) { self.last_flush = now; FlushDecision::End diff --git a/bottlecap/src/lifecycle/invocation_times.rs b/bottlecap/src/lifecycle/invocation_times.rs index 4ddea1de1..ea69bf337 100644 --- a/bottlecap/src/lifecycle/invocation_times.rs +++ b/bottlecap/src/lifecycle/invocation_times.rs @@ -1,4 +1,4 @@ -use crate::config::flush_strategy::{FlushStrategy, PeriodicStrategy}; +use crate::config::flush_strategy::{ConcreteFlushStrategy, PeriodicStrategy}; const TWENTY_SECONDS: u64 = 20 * 1000; const LOOKBACK_COUNT: usize = 20; @@ -23,15 +23,22 @@ impl InvocationTimes { self.head = (self.head + 1) % LOOKBACK_COUNT; } - pub(crate) fn should_adapt(&self, now: u64, flush_timeout: u64) -> FlushStrategy { - // If the buffer isn't full, then we haven't seen enough invocations, so we should flush. + // Translate FlushStrategy::Default to a ConcreteFlushStrategy, based on past invocation times. + pub(crate) fn evaluate_default_strategy(&self, now: u64, flush_timeout: u64) -> ConcreteFlushStrategy { + // If the buffer isn't full, then we haven't seen enough invocations, so we should flush + // at the end of the invocation. for idx in self.head..LOOKBACK_COUNT { if self.times[idx] == 0 { - return FlushStrategy::End; + return ConcreteFlushStrategy::End; } } - // Now we've seen at least 20 invocations. Switch to periodic if we're invoked at least once every 2 minutes. + // Now we've seen at least 20 invocations. Possible cases: + // 1. If the average time between invocations is longer than 2 minutes, stick to End strategy. + // 2. If average interval is shorter than 2 minutes: + // 2.1 If it's very short, use the continuous strategy to minimize delaying the next invocation. + // 2.2 If it's not too short, use the periodic strategy to minimize the risk that + // flushing is delayed due to the Lambda environment being frozen between invocations. // We get the average time between each invocation by taking the difference between newest (`now`) and the // oldest invocation in the buffer, then dividing by `LOOKBACK_COUNT - 1`. let oldest = self.times[self.head]; @@ -40,22 +47,23 @@ impl InvocationTimes { let should_adapt = (elapsed as f64 / (LOOKBACK_COUNT - 1) as f64) < ONE_TWENTY_SECONDS; if should_adapt { // Both units here are in seconds + // TODO: What does this mean? if elapsed < flush_timeout { - return FlushStrategy::Continuously(PeriodicStrategy { + return ConcreteFlushStrategy::Continuously(PeriodicStrategy { interval: TWENTY_SECONDS, }); } - return FlushStrategy::Periodically(PeriodicStrategy { + return ConcreteFlushStrategy::Periodically(PeriodicStrategy { interval: TWENTY_SECONDS, }); } - FlushStrategy::End + ConcreteFlushStrategy::End } } #[cfg(test)] mod tests { - use crate::config::flush_strategy::{FlushStrategy, PeriodicStrategy}; + use crate::config::flush_strategy::{ConcreteFlushStrategy, PeriodicStrategy}; use crate::lifecycle::invocation_times::{self, TWENTY_SECONDS}; #[test] @@ -75,7 +83,7 @@ mod tests { invocation_times.add(timestamp); assert_eq!(invocation_times.times[0], timestamp); assert_eq!(invocation_times.head, 1); - assert_eq!(invocation_times.should_adapt(1, 60), FlushStrategy::End); + assert_eq!(invocation_times.evaluate_default_strategy(1, 60), ConcreteFlushStrategy::End); } #[test] @@ -88,8 +96,8 @@ mod tests { assert_eq!(invocation_times.times[0], 20); assert_eq!(invocation_times.head, 1); assert_eq!( - invocation_times.should_adapt(21, 60), - FlushStrategy::Continuously(PeriodicStrategy { + invocation_times.evaluate_default_strategy(21, 60), + ConcreteFlushStrategy::Continuously(PeriodicStrategy { interval: TWENTY_SECONDS }) ); @@ -105,8 +113,8 @@ mod tests { assert_eq!(invocation_times.times[0], 20); assert_eq!(invocation_times.head, 1); assert_eq!( - invocation_times.should_adapt(21, 1), - FlushStrategy::Periodically(PeriodicStrategy { + invocation_times.evaluate_default_strategy(21, 1), + ConcreteFlushStrategy::Periodically(PeriodicStrategy { interval: TWENTY_SECONDS }) ); @@ -122,7 +130,7 @@ mod tests { // should wrap around assert_eq!(invocation_times.times[0], 5019); assert_eq!(invocation_times.head, 1); - assert_eq!(invocation_times.should_adapt(10000, 60), FlushStrategy::End); + assert_eq!(invocation_times.evaluate_default_strategy(10000, 60), ConcreteFlushStrategy::End); } #[test] @@ -140,8 +148,8 @@ mod tests { 1901 ); assert_eq!( - invocation_times.should_adapt(2501, 60), - FlushStrategy::Periodically(PeriodicStrategy { + invocation_times.evaluate_default_strategy(2501, 60), + ConcreteFlushStrategy::Periodically(PeriodicStrategy { interval: TWENTY_SECONDS }) ); @@ -161,6 +169,6 @@ mod tests { invocation_times.times[invocation_times::LOOKBACK_COUNT - 1], 2471 ); - assert_eq!(invocation_times.should_adapt(3251, 60), FlushStrategy::End); + assert_eq!(invocation_times.evaluate_default_strategy(3251, 60), ConcreteFlushStrategy::End); } } From 7ec82b8d2d55dba33f0570d9357565cb29088c2d Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Fri, 11 Jul 2025 16:43:38 -0400 Subject: [PATCH 2/5] fmt --- bottlecap/src/lifecycle/flush_control.rs | 4 +++- bottlecap/src/lifecycle/invocation_times.rs | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/bottlecap/src/lifecycle/flush_control.rs b/bottlecap/src/lifecycle/flush_control.rs index 2365c2717..64e6cb422 100644 --- a/bottlecap/src/lifecycle/flush_control.rs +++ b/bottlecap/src/lifecycle/flush_control.rs @@ -69,7 +69,9 @@ impl FlushControl { .as_secs(); self.invocation_times.add(now); let evaluated_flush_strategy = if self.flush_strategy == FlushStrategy::Default { - &self.invocation_times.evaluate_default_strategy(now, self.flush_timeout) + &self + .invocation_times + .evaluate_default_strategy(now, self.flush_timeout) } else { // User specified one &self.flush_strategy.into() diff --git a/bottlecap/src/lifecycle/invocation_times.rs b/bottlecap/src/lifecycle/invocation_times.rs index ea69bf337..6456fe1ec 100644 --- a/bottlecap/src/lifecycle/invocation_times.rs +++ b/bottlecap/src/lifecycle/invocation_times.rs @@ -24,7 +24,11 @@ impl InvocationTimes { } // Translate FlushStrategy::Default to a ConcreteFlushStrategy, based on past invocation times. - pub(crate) fn evaluate_default_strategy(&self, now: u64, flush_timeout: u64) -> ConcreteFlushStrategy { + pub(crate) fn evaluate_default_strategy( + &self, + now: u64, + flush_timeout: u64, + ) -> ConcreteFlushStrategy { // If the buffer isn't full, then we haven't seen enough invocations, so we should flush // at the end of the invocation. for idx in self.head..LOOKBACK_COUNT { @@ -83,7 +87,10 @@ mod tests { invocation_times.add(timestamp); assert_eq!(invocation_times.times[0], timestamp); assert_eq!(invocation_times.head, 1); - assert_eq!(invocation_times.evaluate_default_strategy(1, 60), ConcreteFlushStrategy::End); + assert_eq!( + invocation_times.evaluate_default_strategy(1, 60), + ConcreteFlushStrategy::End + ); } #[test] @@ -130,7 +137,10 @@ mod tests { // should wrap around assert_eq!(invocation_times.times[0], 5019); assert_eq!(invocation_times.head, 1); - assert_eq!(invocation_times.evaluate_default_strategy(10000, 60), ConcreteFlushStrategy::End); + assert_eq!( + invocation_times.evaluate_default_strategy(10000, 60), + ConcreteFlushStrategy::End + ); } #[test] @@ -169,6 +179,9 @@ mod tests { invocation_times.times[invocation_times::LOOKBACK_COUNT - 1], 2471 ); - assert_eq!(invocation_times.evaluate_default_strategy(3251, 60), ConcreteFlushStrategy::End); + assert_eq!( + invocation_times.evaluate_default_strategy(3251, 60), + ConcreteFlushStrategy::End + ); } } From 60ad35ce36cef3adf0963549a6a980c43e6ec58f Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Mon, 14 Jul 2025 12:06:14 -0400 Subject: [PATCH 3/5] Make evaluate_concrete_strategy() accept FlushStrategy param --- bottlecap/src/config/flush_strategy.rs | 12 --- bottlecap/src/lifecycle/flush_control.rs | 15 ++-- bottlecap/src/lifecycle/invocation_times.rs | 94 ++++++++++++--------- 3 files changed, 59 insertions(+), 62 deletions(-) diff --git a/bottlecap/src/config/flush_strategy.rs b/bottlecap/src/config/flush_strategy.rs index e73795d1c..51e9710eb 100644 --- a/bottlecap/src/config/flush_strategy.rs +++ b/bottlecap/src/config/flush_strategy.rs @@ -32,18 +32,6 @@ pub enum ConcreteFlushStrategy { Continuously(PeriodicStrategy), } -impl From for ConcreteFlushStrategy { - fn from(strategy: FlushStrategy) -> ConcreteFlushStrategy { - match strategy { - FlushStrategy::Periodically(p) => ConcreteFlushStrategy::Periodically(p), - FlushStrategy::End => ConcreteFlushStrategy::End, - FlushStrategy::Continuously(p) => ConcreteFlushStrategy::Continuously(p), - FlushStrategy::EndPeriodically(p) => ConcreteFlushStrategy::EndPeriodically(p), - FlushStrategy::Default => unreachable!("Default strategy is not allowed"), - } - } -} - // Deserialize for FlushStrategy // Flush Strategy can be either "end", "end,", or "periodically," impl<'de> Deserialize<'de> for FlushStrategy { diff --git a/bottlecap/src/lifecycle/flush_control.rs b/bottlecap/src/lifecycle/flush_control.rs index 64e6cb422..2d5369580 100644 --- a/bottlecap/src/lifecycle/flush_control.rs +++ b/bottlecap/src/lifecycle/flush_control.rs @@ -68,15 +68,12 @@ impl FlushControl { .expect("unable to poll clock, unrecoverable") .as_secs(); self.invocation_times.add(now); - let evaluated_flush_strategy = if self.flush_strategy == FlushStrategy::Default { - &self - .invocation_times - .evaluate_default_strategy(now, self.flush_timeout) - } else { - // User specified one - &self.flush_strategy.into() - }; - match evaluated_flush_strategy { + let concrete_flush_strategy = self.invocation_times.evaluate_concrete_strategy( + now, + self.flush_timeout, + self.flush_strategy, + ); + match concrete_flush_strategy { ConcreteFlushStrategy::Periodically(strategy) => { if self.interval_passed(now, strategy.interval) { self.last_flush = now; diff --git a/bottlecap/src/lifecycle/invocation_times.rs b/bottlecap/src/lifecycle/invocation_times.rs index 6456fe1ec..4fabe8e42 100644 --- a/bottlecap/src/lifecycle/invocation_times.rs +++ b/bottlecap/src/lifecycle/invocation_times.rs @@ -1,4 +1,4 @@ -use crate::config::flush_strategy::{ConcreteFlushStrategy, PeriodicStrategy}; +use crate::config::flush_strategy::{ConcreteFlushStrategy, FlushStrategy, PeriodicStrategy}; const TWENTY_SECONDS: u64 = 20 * 1000; const LOOKBACK_COUNT: usize = 20; @@ -23,51 +23,63 @@ impl InvocationTimes { self.head = (self.head + 1) % LOOKBACK_COUNT; } - // Translate FlushStrategy::Default to a ConcreteFlushStrategy, based on past invocation times. - pub(crate) fn evaluate_default_strategy( + // Translate FlushStrategy to a ConcreteFlushStrategy + // For FlushStrategy::Default, evaluate based on past invocation times. Otherwise, return the + // strategy as is. + pub(crate) fn evaluate_concrete_strategy( &self, now: u64, flush_timeout: u64, + flush_strategy: FlushStrategy, ) -> ConcreteFlushStrategy { - // If the buffer isn't full, then we haven't seen enough invocations, so we should flush - // at the end of the invocation. - for idx in self.head..LOOKBACK_COUNT { - if self.times[idx] == 0 { - return ConcreteFlushStrategy::End; + match flush_strategy { + FlushStrategy::Periodically(p) => ConcreteFlushStrategy::Periodically(p), + FlushStrategy::End => ConcreteFlushStrategy::End, + FlushStrategy::Continuously(p) => ConcreteFlushStrategy::Continuously(p), + FlushStrategy::EndPeriodically(p) => ConcreteFlushStrategy::EndPeriodically(p), + FlushStrategy::Default => { + // If the buffer isn't full, then we haven't seen enough invocations, so we should flush + // at the end of the invocation. + for idx in self.head..LOOKBACK_COUNT { + if self.times[idx] == 0 { + return ConcreteFlushStrategy::End; + } + } + + // Now we've seen at least 20 invocations. Possible cases: + // 1. If the average time between invocations is longer than 2 minutes, stick to End strategy. + // 2. If average interval is shorter than 2 minutes: + // 2.1 If it's very short, use the continuous strategy to minimize delaying the next invocation. + // 2.2 If it's not too short, use the periodic strategy to minimize the risk that + // flushing is delayed due to the Lambda environment being frozen between invocations. + // We get the average time between each invocation by taking the difference between newest (`now`) and the + // oldest invocation in the buffer, then dividing by `LOOKBACK_COUNT - 1`. + let oldest = self.times[self.head]; + + let elapsed = now - oldest; + let should_adapt = + (elapsed as f64 / (LOOKBACK_COUNT - 1) as f64) < ONE_TWENTY_SECONDS; + if should_adapt { + // Both units here are in seconds + // TODO: What does this mean? + if elapsed < flush_timeout { + return ConcreteFlushStrategy::Continuously(PeriodicStrategy { + interval: TWENTY_SECONDS, + }); + } + return ConcreteFlushStrategy::Periodically(PeriodicStrategy { + interval: TWENTY_SECONDS, + }); + } + ConcreteFlushStrategy::End } } - - // Now we've seen at least 20 invocations. Possible cases: - // 1. If the average time between invocations is longer than 2 minutes, stick to End strategy. - // 2. If average interval is shorter than 2 minutes: - // 2.1 If it's very short, use the continuous strategy to minimize delaying the next invocation. - // 2.2 If it's not too short, use the periodic strategy to minimize the risk that - // flushing is delayed due to the Lambda environment being frozen between invocations. - // We get the average time between each invocation by taking the difference between newest (`now`) and the - // oldest invocation in the buffer, then dividing by `LOOKBACK_COUNT - 1`. - let oldest = self.times[self.head]; - - let elapsed = now - oldest; - let should_adapt = (elapsed as f64 / (LOOKBACK_COUNT - 1) as f64) < ONE_TWENTY_SECONDS; - if should_adapt { - // Both units here are in seconds - // TODO: What does this mean? - if elapsed < flush_timeout { - return ConcreteFlushStrategy::Continuously(PeriodicStrategy { - interval: TWENTY_SECONDS, - }); - } - return ConcreteFlushStrategy::Periodically(PeriodicStrategy { - interval: TWENTY_SECONDS, - }); - } - ConcreteFlushStrategy::End } } #[cfg(test)] mod tests { - use crate::config::flush_strategy::{ConcreteFlushStrategy, PeriodicStrategy}; + use crate::config::flush_strategy::{ConcreteFlushStrategy, FlushStrategy, PeriodicStrategy}; use crate::lifecycle::invocation_times::{self, TWENTY_SECONDS}; #[test] @@ -88,7 +100,7 @@ mod tests { assert_eq!(invocation_times.times[0], timestamp); assert_eq!(invocation_times.head, 1); assert_eq!( - invocation_times.evaluate_default_strategy(1, 60), + invocation_times.evaluate_concrete_strategy(1, 60, FlushStrategy::Default), ConcreteFlushStrategy::End ); } @@ -103,7 +115,7 @@ mod tests { assert_eq!(invocation_times.times[0], 20); assert_eq!(invocation_times.head, 1); assert_eq!( - invocation_times.evaluate_default_strategy(21, 60), + invocation_times.evaluate_concrete_strategy(21, 60, FlushStrategy::Default), ConcreteFlushStrategy::Continuously(PeriodicStrategy { interval: TWENTY_SECONDS }) @@ -120,7 +132,7 @@ mod tests { assert_eq!(invocation_times.times[0], 20); assert_eq!(invocation_times.head, 1); assert_eq!( - invocation_times.evaluate_default_strategy(21, 1), + invocation_times.evaluate_concrete_strategy(21, 1, FlushStrategy::Default), ConcreteFlushStrategy::Periodically(PeriodicStrategy { interval: TWENTY_SECONDS }) @@ -138,7 +150,7 @@ mod tests { assert_eq!(invocation_times.times[0], 5019); assert_eq!(invocation_times.head, 1); assert_eq!( - invocation_times.evaluate_default_strategy(10000, 60), + invocation_times.evaluate_concrete_strategy(10000, 60, FlushStrategy::Default), ConcreteFlushStrategy::End ); } @@ -158,7 +170,7 @@ mod tests { 1901 ); assert_eq!( - invocation_times.evaluate_default_strategy(2501, 60), + invocation_times.evaluate_concrete_strategy(2501, 60, FlushStrategy::Default), ConcreteFlushStrategy::Periodically(PeriodicStrategy { interval: TWENTY_SECONDS }) @@ -180,7 +192,7 @@ mod tests { 2471 ); assert_eq!( - invocation_times.evaluate_default_strategy(3251, 60), + invocation_times.evaluate_concrete_strategy(3251, 60, FlushStrategy::Default), ConcreteFlushStrategy::End ); } From a6991f60c57a69cbcf354774dfdbd9c5b0a36222 Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Mon, 14 Jul 2025 13:28:04 -0400 Subject: [PATCH 4/5] Add comment --- bottlecap/src/lifecycle/flush_control.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bottlecap/src/lifecycle/flush_control.rs b/bottlecap/src/lifecycle/flush_control.rs index 2d5369580..6af1f88ad 100644 --- a/bottlecap/src/lifecycle/flush_control.rs +++ b/bottlecap/src/lifecycle/flush_control.rs @@ -52,8 +52,9 @@ impl FlushControl { i.set_missed_tick_behavior(Skip); i } - // TODO: Why is this 15 minutes? FlushStrategy::End => { + // Set the race flush interval to the maximum value of Lambda timeout, so flush will + // only happen at the end of the invocation, and race flush will never happen. tokio::time::interval(tokio::time::Duration::from_millis(FIFTEEN_MINUTES)) } } From e9d04dc8fa66ec8dd2a6ccd8781778954580b713 Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Mon, 21 Jul 2025 11:29:50 -0400 Subject: [PATCH 5/5] Remove TODO --- bottlecap/src/lifecycle/invocation_times.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bottlecap/src/lifecycle/invocation_times.rs b/bottlecap/src/lifecycle/invocation_times.rs index 4fabe8e42..dca4777e1 100644 --- a/bottlecap/src/lifecycle/invocation_times.rs +++ b/bottlecap/src/lifecycle/invocation_times.rs @@ -61,7 +61,6 @@ impl InvocationTimes { (elapsed as f64 / (LOOKBACK_COUNT - 1) as f64) < ONE_TWENTY_SECONDS; if should_adapt { // Both units here are in seconds - // TODO: What does this mean? if elapsed < flush_timeout { return ConcreteFlushStrategy::Continuously(PeriodicStrategy { interval: TWENTY_SECONDS,