1- use crate :: config:: flush_strategy:: { FlushStrategy , PeriodicStrategy } ;
1+ use crate :: config:: flush_strategy:: { ConcreteFlushStrategy , FlushStrategy , PeriodicStrategy } ;
22
33const TWENTY_SECONDS : u64 = 20 * 1000 ;
44const LOOKBACK_COUNT : usize = 20 ;
@@ -23,39 +23,62 @@ impl InvocationTimes {
2323 self . head = ( self . head + 1 ) % LOOKBACK_COUNT ;
2424 }
2525
26- pub ( crate ) fn should_adapt ( & self , now : u64 , flush_timeout : u64 ) -> FlushStrategy {
27- // If the buffer isn't full, then we haven't seen enough invocations, so we should flush.
28- for idx in self . head ..LOOKBACK_COUNT {
29- if self . times [ idx] == 0 {
30- return FlushStrategy :: End ;
26+ // Translate FlushStrategy to a ConcreteFlushStrategy
27+ // For FlushStrategy::Default, evaluate based on past invocation times. Otherwise, return the
28+ // strategy as is.
29+ pub ( crate ) fn evaluate_concrete_strategy (
30+ & self ,
31+ now : u64 ,
32+ flush_timeout : u64 ,
33+ flush_strategy : FlushStrategy ,
34+ ) -> ConcreteFlushStrategy {
35+ match flush_strategy {
36+ FlushStrategy :: Periodically ( p) => ConcreteFlushStrategy :: Periodically ( p) ,
37+ FlushStrategy :: End => ConcreteFlushStrategy :: End ,
38+ FlushStrategy :: Continuously ( p) => ConcreteFlushStrategy :: Continuously ( p) ,
39+ FlushStrategy :: EndPeriodically ( p) => ConcreteFlushStrategy :: EndPeriodically ( p) ,
40+ FlushStrategy :: Default => {
41+ // If the buffer isn't full, then we haven't seen enough invocations, so we should flush
42+ // at the end of the invocation.
43+ for idx in self . head ..LOOKBACK_COUNT {
44+ if self . times [ idx] == 0 {
45+ return ConcreteFlushStrategy :: End ;
46+ }
47+ }
48+
49+ // Now we've seen at least 20 invocations. Possible cases:
50+ // 1. If the average time between invocations is longer than 2 minutes, stick to End strategy.
51+ // 2. If average interval is shorter than 2 minutes:
52+ // 2.1 If it's very short, use the continuous strategy to minimize delaying the next invocation.
53+ // 2.2 If it's not too short, use the periodic strategy to minimize the risk that
54+ // flushing is delayed due to the Lambda environment being frozen between invocations.
55+ // We get the average time between each invocation by taking the difference between newest (`now`) and the
56+ // oldest invocation in the buffer, then dividing by `LOOKBACK_COUNT - 1`.
57+ let oldest = self . times [ self . head ] ;
58+
59+ let elapsed = now - oldest;
60+ let should_adapt =
61+ ( elapsed as f64 / ( LOOKBACK_COUNT - 1 ) as f64 ) < ONE_TWENTY_SECONDS ;
62+ if should_adapt {
63+ // Both units here are in seconds
64+ if elapsed < flush_timeout {
65+ return ConcreteFlushStrategy :: Continuously ( PeriodicStrategy {
66+ interval : TWENTY_SECONDS ,
67+ } ) ;
68+ }
69+ return ConcreteFlushStrategy :: Periodically ( PeriodicStrategy {
70+ interval : TWENTY_SECONDS ,
71+ } ) ;
72+ }
73+ ConcreteFlushStrategy :: End
3174 }
3275 }
33-
34- // Now we've seen at least 20 invocations. Switch to periodic if we're invoked at least once every 2 minutes.
35- // We get the average time between each invocation by taking the difference between newest (`now`) and the
36- // oldest invocation in the buffer, then dividing by `LOOKBACK_COUNT - 1`.
37- let oldest = self . times [ self . head ] ;
38-
39- let elapsed = now - oldest;
40- let should_adapt = ( elapsed as f64 / ( LOOKBACK_COUNT - 1 ) as f64 ) < ONE_TWENTY_SECONDS ;
41- if should_adapt {
42- // Both units here are in seconds
43- if elapsed < flush_timeout {
44- return FlushStrategy :: Continuously ( PeriodicStrategy {
45- interval : TWENTY_SECONDS ,
46- } ) ;
47- }
48- return FlushStrategy :: Periodically ( PeriodicStrategy {
49- interval : TWENTY_SECONDS ,
50- } ) ;
51- }
52- FlushStrategy :: End
5376 }
5477}
5578
5679#[ cfg( test) ]
5780mod tests {
58- use crate :: config:: flush_strategy:: { FlushStrategy , PeriodicStrategy } ;
81+ use crate :: config:: flush_strategy:: { ConcreteFlushStrategy , FlushStrategy , PeriodicStrategy } ;
5982 use crate :: lifecycle:: invocation_times:: { self , TWENTY_SECONDS } ;
6083
6184 #[ test]
@@ -75,7 +98,10 @@ mod tests {
7598 invocation_times. add ( timestamp) ;
7699 assert_eq ! ( invocation_times. times[ 0 ] , timestamp) ;
77100 assert_eq ! ( invocation_times. head, 1 ) ;
78- assert_eq ! ( invocation_times. should_adapt( 1 , 60 ) , FlushStrategy :: End ) ;
101+ assert_eq ! (
102+ invocation_times. evaluate_concrete_strategy( 1 , 60 , FlushStrategy :: Default ) ,
103+ ConcreteFlushStrategy :: End
104+ ) ;
79105 }
80106
81107 #[ test]
@@ -88,8 +114,8 @@ mod tests {
88114 assert_eq ! ( invocation_times. times[ 0 ] , 20 ) ;
89115 assert_eq ! ( invocation_times. head, 1 ) ;
90116 assert_eq ! (
91- invocation_times. should_adapt ( 21 , 60 ) ,
92- FlushStrategy :: Continuously ( PeriodicStrategy {
117+ invocation_times. evaluate_concrete_strategy ( 21 , 60 , FlushStrategy :: Default ) ,
118+ ConcreteFlushStrategy :: Continuously ( PeriodicStrategy {
93119 interval: TWENTY_SECONDS
94120 } )
95121 ) ;
@@ -105,8 +131,8 @@ mod tests {
105131 assert_eq ! ( invocation_times. times[ 0 ] , 20 ) ;
106132 assert_eq ! ( invocation_times. head, 1 ) ;
107133 assert_eq ! (
108- invocation_times. should_adapt ( 21 , 1 ) ,
109- FlushStrategy :: Periodically ( PeriodicStrategy {
134+ invocation_times. evaluate_concrete_strategy ( 21 , 1 , FlushStrategy :: Default ) ,
135+ ConcreteFlushStrategy :: Periodically ( PeriodicStrategy {
110136 interval: TWENTY_SECONDS
111137 } )
112138 ) ;
@@ -122,7 +148,10 @@ mod tests {
122148 // should wrap around
123149 assert_eq ! ( invocation_times. times[ 0 ] , 5019 ) ;
124150 assert_eq ! ( invocation_times. head, 1 ) ;
125- assert_eq ! ( invocation_times. should_adapt( 10000 , 60 ) , FlushStrategy :: End ) ;
151+ assert_eq ! (
152+ invocation_times. evaluate_concrete_strategy( 10000 , 60 , FlushStrategy :: Default ) ,
153+ ConcreteFlushStrategy :: End
154+ ) ;
126155 }
127156
128157 #[ test]
@@ -140,8 +169,8 @@ mod tests {
140169 1901
141170 ) ;
142171 assert_eq ! (
143- invocation_times. should_adapt ( 2501 , 60 ) ,
144- FlushStrategy :: Periodically ( PeriodicStrategy {
172+ invocation_times. evaluate_concrete_strategy ( 2501 , 60 , FlushStrategy :: Default ) ,
173+ ConcreteFlushStrategy :: Periodically ( PeriodicStrategy {
145174 interval: TWENTY_SECONDS
146175 } )
147176 ) ;
@@ -161,6 +190,9 @@ mod tests {
161190 invocation_times. times[ invocation_times:: LOOKBACK_COUNT - 1 ] ,
162191 2471
163192 ) ;
164- assert_eq ! ( invocation_times. should_adapt( 3251 , 60 ) , FlushStrategy :: End ) ;
193+ assert_eq ! (
194+ invocation_times. evaluate_concrete_strategy( 3251 , 60 , FlushStrategy :: Default ) ,
195+ ConcreteFlushStrategy :: End
196+ ) ;
165197 }
166198}
0 commit comments