1import * as _ from 'lodash-es' 4type RlHistRec = {lastRunAtMs: number, backoffNo: number, numSilenced: number, silencedSamples?: unknown[]} 6export const getExpBackoffLimited = ({ 7 cache_key, rlHistH, backoffBaseMs=60 * 1000, 8 recoveryPeriodMs=1000 * 60 * 60 * 24, 9 backoffCapMs=recoveryPeriodMs, 10 silencedSample, maxSilencedSamples=10, 11}: {cache_key: string, rlHistH: Record<string, RlHistRec>, backoffBaseMs?: number, recoveryPeriodMs?: number, backoffCapMs?: number, silencedSample?: unknown, maxSilencedSamples?: number}) => { 14 let rec: RlHistRec | undefined = rlHistH[cache_key] 23 ;({lastRunAtMs, backoffNo, numSilenced} = rec) 25 const minRecovResetMs = now - recoveryPeriodMs 26 if (lastRunAtMs < minRecovResetMs) { 27 delete rlHistH[cache_key] 33 // cap the exponential at backoffCapMs (default = recoveryPeriodMs, ~daily) so a PERSISTENT error 34 // keeps reminding once/day instead of fading below daily as 2^backoffNo grows unbounded. 35 const backoffWaitMs = Math.min(backoffBaseMs * Math.pow(2, backoffNo), backoffCapMs) 37 const mustWaitUntilMs = lastRunAtMs + backoffWaitMs 38 const silencedForMs = mustWaitUntilMs - now 39 const isLimited = silencedForMs > 0 44 if (silencedSample !== undefined) { 45 ;(rec.silencedSamples ||= []).push(silencedSample) 46 if (rec.silencedSamples.length > maxSilencedSamples) rec.silencedSamples.length = maxSilencedSamples 48 return {isLimited, backoffNo, numSilenced} 52 const prevSilencedSamples = rec?.silencedSamples 56 rlHistH[cache_key] = { 62 return {isLimited: false, backoffNo, numSilenced, silencedSamples: prevSilencedSamples}