@@ -53,7 +53,7 @@ const DEFAULT_JITTER_FACTOR = 1.0;
5353/*!
5454 * The timeout handler used by `ExponentialBackoff`.
5555 */
56- let delayExecution = setTimeout ;
56+ let delayExecution : typeof setTimeout = setTimeout ;
5757
5858/**
5959 * Allows overriding of the timeout handler used by the exponential backoff
@@ -64,10 +64,31 @@ let delayExecution = setTimeout;
6464 * @private
6565 * @param {function } handler A handler than matches the API of `setTimeout()`.
6666 */
67- export function setTimeoutHandler ( handler ) {
67+ export function setTimeoutHandler ( handler : typeof setTimeout ) : void {
6868 delayExecution = handler ;
6969}
7070
71+ /**
72+ * Configuration object to adjust the delays of the exponential backoff
73+ * algorithm.
74+ *
75+ * @private
76+ */
77+ export interface ExponentialBackoffOptions {
78+ /** Optional override for the initial retry delay. */
79+ initialDelayMs ?: number ;
80+ /** Optional override for the exponential backoff factor. */
81+ backoffFactor ?: number ;
82+ /** Optional override for the maximum retry delay. */
83+ maxDelayMs ?: number ;
84+ /**
85+ * Optional override to control the itter factor by which to randomize
86+ * attempts (0 means no randomization, 1.0 means +/-50% randomization). It is
87+ * suggested not to exceed this range.
88+ */
89+ jitterFactor ?: number ;
90+ }
91+
7192/**
7293 * A helper for running delayed tasks following an exponential backoff curve
7394 * between attempts.
@@ -81,70 +102,49 @@ export function setTimeoutHandler(handler) {
81102 */
82103export class ExponentialBackoff {
83104 /**
84- * @param {number= } options.initialDelayMs Optional override for the initial
85- * retry delay.
86- * @param {number= } options.backoffFactor Optional override for the
87- * exponential backoff factor.
88- * @param {number= } options.maxDelayMs Optional override for the maximum
89- * retry delay.
90- * @param {number= } options.jitterFactor Optional override to control the
91- * jitter factor by which to randomize attempts (0 means no randomization,
92- * 1.0 means +/-50% randomization). It is suggested not to exceed this range.
105+ * The initial delay (used as the base delay on the first retry attempt).
106+ * Note that jitter will still be applied, so the actual delay could be as
107+ * little as 0.5*initialDelayMs (based on a jitter factor of 1.0).
108+ */
109+ private readonly initialDelayMs : number ;
110+
111+ /**
112+ * The multiplier to use to determine the extended base delay after each
113+ * attempt.
114+ */
115+ private readonly backoffFactor : number ;
116+
117+ /**
118+ * The maximum base delay after which no further backoff is performed.
119+ * Note that jitter will still be applied, so the actual delay could be as
120+ * much as 1.5*maxDelayMs (based on a jitter factor of 1.0).
121+ */
122+ private readonly maxDelayMs : number ;
123+
124+ /**
125+ * The jitter factor that controls the random distribution of the backoff
126+ * points.
127+ */
128+ private readonly jitterFactor : number ;
129+
130+ /**
131+ * The backoff delay of the current attempt.
93132 */
94- constructor ( options ) {
95- options = options || { } ;
96-
97- /**
98- * The initial delay (used as the base delay on the first retry attempt).
99- * Note that jitter will still be applied, so the actual delay could be as
100- * little as 0.5*initialDelayMs (based on a jitter factor of 1.0).
101- *
102- * @type {number }
103- * @private
104- */
105- this . _initialDelayMs = options . initialDelayMs !== undefined ?
133+ private currentBaseMs = 0 ;
134+
135+ constructor ( options : ExponentialBackoffOptions = { } ) {
136+ this . initialDelayMs = options . initialDelayMs !== undefined ?
106137 options . initialDelayMs :
107138 DEFAULT_BACKOFF_INITIAL_DELAY_MS ;
108-
109- /**
110- * The multiplier to use to determine the extended base delay after each
111- * attempt.
112- * @type {number }
113- * @private
114- */
115- this . _backoffFactor = options . backoffFactor !== undefined ?
139+ this . backoffFactor = options . backoffFactor !== undefined ?
116140 options . backoffFactor :
117141 DEFAULT_BACKOFF_FACTOR ;
118-
119- /**
120- * The maximum base delay after which no further backoff is performed.
121- * Note that jitter will still be applied, so the actual delay could be as
122- * much as 1.5*maxDelayMs (based on a jitter factor of 1.0).
123- *
124- * @type {number }
125- * @private
126- */
127- this . _maxDelayMs = options . maxDelayMs !== undefined ?
142+ this . maxDelayMs = options . maxDelayMs !== undefined ?
128143 options . maxDelayMs :
129144 DEFAULT_BACKOFF_MAX_DELAY_MS ;
130-
131- /**
132- * The jitter factor that controls the random distribution of the backoff
133- * points.
134- *
135- * @type {number }
136- * @private
137- */
138- this . _jitterFactor = options . jitterFactor !== undefined ?
145+ this . jitterFactor = options . jitterFactor !== undefined ?
139146 options . jitterFactor :
140147 DEFAULT_JITTER_FACTOR ;
141-
142- /**
143- * The backoff delay of the current attempt.
144- * @type {number }
145- * @private
146- */
147- this . _currentBaseMs = 0 ;
148148 }
149149
150150 /**
@@ -153,51 +153,41 @@ export class ExponentialBackoff {
153153 * The very next backoffAndWait() will have no delay. If it is called again
154154 * (i.e. due to an error), initialDelayMs (plus jitter) will be used, and
155155 * subsequent ones will increase according to the backoffFactor.
156- *
157- * @private
158156 */
159- reset ( ) {
160- this . _currentBaseMs = 0 ;
157+ private reset ( ) : void {
158+ this . currentBaseMs = 0 ;
161159 }
162160
163161 /**
164162 * Resets the backoff delay to the maximum delay (e.g. for use after a
165163 * RESOURCE_EXHAUSTED error).
166- *
167- * @private
168164 */
169- resetToMax ( ) {
170- this . _currentBaseMs = this . _maxDelayMs ;
165+ private resetToMax ( ) : void {
166+ this . currentBaseMs = this . maxDelayMs ;
171167 }
172168
173169 /**
174170 * Returns a promise that resolves after currentDelayMs, and increases the
175171 * delay for any subsequent attempts.
176172 *
177- * @private
178- * @return {Promise.<void> } A Promise that resolves when the current delay
179- * elapsed.
173+ * @return A Promise that resolves when the current delay elapsed.
180174 */
181- backoffAndWait ( ) {
175+ backoffAndWait ( ) : Promise < void > {
182176 // First schedule using the current base (which may be 0 and should be
183177 // honored as such).
184- const delayWithJitterMs = this . _currentBaseMs + this . _jitterDelayMs ( ) ;
185- if ( this . _currentBaseMs > 0 ) {
178+ const delayWithJitterMs = this . currentBaseMs + this . jitterDelayMs ( ) ;
179+ if ( this . currentBaseMs > 0 ) {
186180 logger (
187- 'ExponentialBackoff.backoffAndWait' ,
181+ 'ExponentialBackoff.backoffAndWait' , null ,
188182 `Backing off for ${ delayWithJitterMs } ms ` +
189- `(base delay: ${ this . _currentBaseMs } ms)` ) ;
183+ `(base delay: ${ this . currentBaseMs } ms)` ) ;
190184 }
191185
192186 // Apply backoff factor to determine next delay and ensure it is within
193187 // bounds.
194- this . _currentBaseMs *= this . _backoffFactor ;
195- if ( this . _currentBaseMs < this . _initialDelayMs ) {
196- this . _currentBaseMs = this . _initialDelayMs ;
197- }
198- if ( this . _currentBaseMs > this . _maxDelayMs ) {
199- this . _currentBaseMs = this . _maxDelayMs ;
200- }
188+ this . currentBaseMs *= this . backoffFactor ;
189+ this . currentBaseMs = Math . max ( this . currentBaseMs , this . initialDelayMs ) ;
190+ this . currentBaseMs = Math . min ( this . currentBaseMs , this . maxDelayMs ) ;
201191
202192 return new Promise ( resolve => {
203193 delayExecution ( resolve , delayWithJitterMs ) ;
@@ -211,7 +201,7 @@ export class ExponentialBackoff {
211201 * @private
212202 * @returns {number } The jitter to apply based on the current delay.
213203 */
214- _jitterDelayMs ( ) {
215- return ( Math . random ( ) - 0.5 ) * this . _jitterFactor * this . _currentBaseMs ;
204+ private jitterDelayMs ( ) {
205+ return ( Math . random ( ) - 0.5 ) * this . jitterFactor * this . currentBaseMs ;
216206 }
217207}
0 commit comments