@@ -222,32 +222,31 @@ class RateByServiceTraceSamplerTest extends DDCoreSpecification {
222222 ' manual.keep' | true | PrioritySampling . USER_KEEP
223223 }
224224
225- def " cappedRate returns new rate when decreasing " () {
225+ def " shouldCap returns false when rate decreases or stays same " () {
226226 expect :
227- RateByServiceTraceSampler . cappedRate(0.8 , 0.4 , true ) == 0.4
228- RateByServiceTraceSampler . cappedRate(0.8 , 0.4 , false ) == 0.4
229- RateByServiceTraceSampler . cappedRate(0.5 , 0.5 , true ) == 0.5
230- RateByServiceTraceSampler . cappedRate(0.5 , 0.5 , false ) == 0.5
227+ ! RateByServiceTraceSampler . shouldCap(0.8 , 0.4 )
228+ ! RateByServiceTraceSampler . shouldCap(0.5 , 0.5 )
229+ ! RateByServiceTraceSampler . shouldCap(0.5 , 1.0 ) // 1.0 <= 0.5 * 2, no cap needed
231230 }
232231
233- def " cappedRate returns new rate when old rate is zero" () {
232+ def " shouldCap returns false when old rate is zero" () {
234233 expect :
235- RateByServiceTraceSampler . cappedRate (0.0 , 0.5 , true ) == 0.5
236- RateByServiceTraceSampler . cappedRate (0.0 , 0.5 , false ) == 0.5
234+ ! RateByServiceTraceSampler . shouldCap (0.0 , 0.5 )
235+ ! RateByServiceTraceSampler . shouldCap (0.0 , 1.0 )
237236 }
238237
239- def " cappedRate caps increase to 2x when canIncrease " () {
238+ def " shouldCap returns true when new rate exceeds 2x old rate " () {
240239 expect :
241- RateByServiceTraceSampler . cappedRate(0.1 , 1.0 , true ) == 0.2
242- RateByServiceTraceSampler . cappedRate(0.2 , 1.0 , true ) == 0.4
243- RateByServiceTraceSampler . cappedRate(0.4 , 1.0 , true ) == 0.8
244- RateByServiceTraceSampler . cappedRate(0.4 , 0.5 , true ) == 0.5
240+ RateByServiceTraceSampler . shouldCap(0.1 , 1.0 )
241+ RateByServiceTraceSampler . shouldCap(0.2 , 0.8 )
242+ RateByServiceTraceSampler . shouldCap(0.1 , 0.3 )
245243 }
246244
247- def " cappedRate holds old rate when canIncrease is false " () {
245+ def " cappedRate returns 2x old rate" () {
248246 expect :
249- RateByServiceTraceSampler . cappedRate(0.1 , 1.0 , false ) == 0.1
250- RateByServiceTraceSampler . cappedRate(0.2 , 0.8 , false ) == 0.2
247+ RateByServiceTraceSampler . cappedRate(0.1 ) == 0.2
248+ RateByServiceTraceSampler . cappedRate(0.2 ) == 0.4
249+ RateByServiceTraceSampler . cappedRate(0.4 ) == 0.8
251250 }
252251
253252 def " ramp-up caps rate increases at 2x per interval" () {
@@ -351,6 +350,43 @@ class RateByServiceTraceSamplerTest extends DDCoreSpecification {
351350 Math . abs(serviceSampler. serviceRates. getSampler(" bar" , " foo" ). sampleRate - 0.4 ) < tolerance
352351 }
353352
353+ def " cooldown not reset by blocked increase" () {
354+ setup :
355+ RateByServiceTraceSampler serviceSampler = new RateByServiceTraceSampler ()
356+ long currentTime = 1_000_000_000L
357+ serviceSampler. nanoTimeSupplier = { -> currentTime }
358+ def tolerance = 0.01
359+
360+ // Set initial low rate
361+ String response = ' {"rate_by_service": {"service:foo,env:bar":0.01}}'
362+ serviceSampler. onResponse(" traces" , serializer. fromJson(response))
363+
364+ expect :
365+ Math . abs(serviceSampler. serviceRates. getSampler(" bar" , " foo" ). sampleRate - 0.01 ) < tolerance
366+
367+ when : " wait for cooldown, apply increase: 0.01 -> 0.02"
368+ currentTime + = RateByServiceTraceSampler . RAMP_UP_INTERVAL_NANOS
369+ response = ' {"rate_by_service": {"service:foo,env:bar":1.0}}'
370+ serviceSampler. onResponse(" traces" , serializer. fromJson(response))
371+
372+ then : " rate is capped at 2x = 0.02"
373+ Math . abs(serviceSampler. serviceRates. getSampler(" bar" , " foo" ). sampleRate - 0.02 ) < tolerance
374+
375+ when : " before cooldown elapses, send another increase - rate should be held and lastCapped NOT reset"
376+ currentTime + = RateByServiceTraceSampler . RAMP_UP_INTERVAL_NANOS / 2
377+ serviceSampler. onResponse(" traces" , serializer. fromJson(response))
378+
379+ then : " rate stays at 0.02 (cooldown)"
380+ Math . abs(serviceSampler. serviceRates. getSampler(" bar" , " foo" ). sampleRate - 0.02 ) < tolerance
381+
382+ when : " wait remaining half of cooldown from the original cap - should allow next ramp-up"
383+ currentTime + = RateByServiceTraceSampler . RAMP_UP_INTERVAL_NANOS / 2
384+ serviceSampler. onResponse(" traces" , serializer. fromJson(response))
385+
386+ then : " rate doubles to 0.04 because lastCapped was NOT reset by the blocked increase"
387+ Math . abs(serviceSampler. serviceRates. getSampler(" bar" , " foo" ). sampleRate - 0.04 ) < tolerance
388+ }
389+
354390 def " not setting forced tracing via tag or setting it wrong value not causing exception" () {
355391 setup :
356392 def sampler = new RateByServiceTraceSampler ()
0 commit comments