@@ -30,7 +30,12 @@ import type { Topology } from '../sdam/topology';
3030import type { ClientSession } from '../sessions' ;
3131import { TimeoutContext } from '../timeout' ;
3232import { RETRY_COST , TOKEN_REFRESH_RATE } from '../token_bucket' ;
33- import { abortable , maxWireVersion , supportsRetryableWrites } from '../utils' ;
33+ import {
34+ abortable ,
35+ exponentialBackoffDelayProvider ,
36+ maxWireVersion ,
37+ supportsRetryableWrites
38+ } from '../utils' ;
3439import { AggregateOperation } from './aggregate' ;
3540import { AbstractOperation , Aspect } from './operation' ;
3641
@@ -246,14 +251,28 @@ async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFro
246251
247252 let systemOverloadRetryAttempt = 0 ;
248253 const maxSystemOverloadRetryAttempts = 5 ;
254+ const backoffDelayProvider = exponentialBackoffDelayProvider (
255+ 10_000 , // MAX_BACKOFF
256+ 100 , // base backoff
257+ 2 // backoff rate
258+ ) ;
249259
250260 while ( true ) {
251261 if ( previousOperationError ) {
252262 if ( previousOperationError . hasErrorLabel ( MongoErrorLabel . SystemOverloadError ) ) {
253263 systemOverloadRetryAttempt += 1 ;
254264
255- // if the SystemOverloadError is not retryable, throw.
256- if ( ! previousOperationError . hasErrorLabel ( MongoErrorLabel . RetryableError ) ) {
265+ if (
266+ // if the SystemOverloadError is not retryable, throw.
267+ ! previousOperationError . hasErrorLabel ( MongoErrorLabel . RetryableError ) ||
268+ ! (
269+ // if retryable writes or reads are not configured, throw.
270+ (
271+ ( hasReadAspect && topology . s . options . retryReads ) ||
272+ ( hasWriteAspect && topology . s . options . retryWrites )
273+ )
274+ )
275+ ) {
257276 throw previousOperationError ;
258277 }
259278
@@ -262,12 +281,7 @@ async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFro
262281 throw previousOperationError ;
263282 }
264283
265- const delayMS =
266- Math . random ( ) *
267- Math . min (
268- 10_000 , // MAX_BACKOFF,
269- 100 * 2 ** systemOverloadRetryAttempt
270- ) ;
284+ const { value : delayMS } = backoffDelayProvider . next ( ) ;
271285
272286 // if the delay would exhaust the CSOT timeout, short-circuit.
273287 if ( timeoutContext . csotEnabled ( ) && delayMS > timeoutContext . remainingTimeMS ) {
0 commit comments