Skip to content

Commit b091159

Browse files
retryability cleanup changes
1 parent 994f0fc commit b091159

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

@@ -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) {

src/utils.ts

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

0 commit comments

Comments
 (0)