Skip to content

Commit c8ccbca

Browse files
retryability cleanup changes
1 parent 3881d6a commit c8ccbca

File tree

2 files changed

+33
-9
lines changed

2 files changed

+33
-9
lines changed

src/operations/execute_operation.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ import type { Topology } from '../sdam/topology';
3030
import type { ClientSession } from '../sessions';
3131
import { TimeoutContext } from '../timeout';
3232
import { 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';
3439
import { AggregateOperation } from './aggregate';
3540
import { AbstractOperation, Aspect } from './operation';
3641

@@ -245,14 +250,28 @@ async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFro
245250

246251
let systemOverloadRetryAttempt = 0;
247252
const maxSystemOverloadRetryAttempts = 5;
253+
const backoffDelayProvider = exponentialBackoffDelayProvider(
254+
10_000, // MAX_BACKOFF
255+
100, // base backoff
256+
2 // backoff rate
257+
);
248258

249259
while (true) {
250260
if (previousOperationError) {
251261
if (previousOperationError.hasErrorLabel(MongoErrorLabel.SystemOverloadError)) {
252262
systemOverloadRetryAttempt += 1;
253263

254-
// if the SystemOverloadError is not retryable, throw.
255-
if (!previousOperationError.hasErrorLabel(MongoErrorLabel.RetryableError)) {
264+
if (
265+
// if the SystemOverloadError is not retryable, throw.
266+
!previousOperationError.hasErrorLabel(MongoErrorLabel.RetryableError) ||
267+
!(
268+
// if retryable writes or reads are not configured, throw.
269+
(
270+
(hasReadAspect && topology.s.options.retryReads) ||
271+
(hasWriteAspect && topology.s.options.retryWrites)
272+
)
273+
)
274+
) {
256275
throw previousOperationError;
257276
}
258277

@@ -261,12 +280,7 @@ async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFro
261280
throw previousOperationError;
262281
}
263282

264-
const delayMS =
265-
Math.random() *
266-
Math.min(
267-
10_000, // MAX_BACKOFF,
268-
100 * 2 ** systemOverloadRetryAttempt
269-
);
283+
const { value: delayMS } = backoffDelayProvider.next();
270284

271285
// if the delay would exhaust the CSOT timeout, short-circuit.
272286
if (timeoutContext.csotEnabled() && delayMS > timeoutContext.remainingTimeMS) {

src/utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,3 +1428,13 @@ export async function abortable<T>(
14281428
abortListener?.[kDispose]();
14291429
}
14301430
}
1431+
1432+
export function* exponentialBackoffDelayProvider(
1433+
maxBackoff: number,
1434+
baseBackoff: number,
1435+
backoffIncreaseRate: number
1436+
): Generator<number> {
1437+
for (let i = 0; ; i++) {
1438+
yield Math.random() * Math.min(maxBackoff, baseBackoff * backoffIncreaseRate ** i);
1439+
}
1440+
}

0 commit comments

Comments
 (0)