Skip to content

Commit 734e1d9

Browse files
authored
chore: Add max retry interval for client (#883)
1 parent ed7f61a commit 734e1d9

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

packages/client/src/grpc-retry.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ export interface BackoffOptions {
4343
* The default is 1 second for RESOURCE_EXHAUSTED errors and 20 millis for other retryable errors.
4444
*/
4545
initialIntervalMs(status: StatusObject): number;
46+
47+
/**
48+
* Function that returns the "maximum" backoff interval based on the returned status.
49+
*
50+
* The default is 10 seconds regardless of the status.
51+
*/
52+
maxIntervalMs(status: StatusObject): number;
4653
}
4754

4855
/**
@@ -59,17 +66,20 @@ function withDefaultBackoffOptions({
5966
factor: factor ?? 2,
6067
maxJitter: maxJitter ?? 0.1,
6168
initialIntervalMs: initialIntervalMs ?? defaultInitialIntervalMs,
69+
maxIntervalMs() {
70+
return 10_000;
71+
},
6272
};
6373
}
6474

6575
/**
6676
* Generates the default retry behavior based on given backoff options
6777
*/
6878
export function defaultGrpcRetryOptions(options: Partial<BackoffOptions> = {}): GrpcRetryOptions {
69-
const { maxAttempts, factor, maxJitter, initialIntervalMs } = withDefaultBackoffOptions(options);
79+
const { maxAttempts, factor, maxJitter, initialIntervalMs, maxIntervalMs } = withDefaultBackoffOptions(options);
7080
return {
7181
delayFunction(attempt, status) {
72-
return factor ** attempt * initialIntervalMs(status) * jitter(maxJitter);
82+
return Math.min(maxIntervalMs(status), factor ** attempt * initialIntervalMs(status)) * jitter(maxJitter);
7383
},
7484
retryableDecider(attempt, status) {
7585
return attempt < maxAttempts && isRetryableError(status);
@@ -116,7 +126,7 @@ function defaultInitialIntervalMs({ code }: StatusObject) {
116126
*
117127
* @param retryOptions Options for the retry interceptor
118128
*/
119-
export function makeGrpcRetryInterceptor({ retryableDecider, delayFunction }: GrpcRetryOptions): Interceptor {
129+
export function makeGrpcRetryInterceptor(retryOptions: GrpcRetryOptions): Interceptor {
120130
return (options, nextCall) => {
121131
let savedSendMessage: any;
122132
let savedReceiveMessage: any;
@@ -147,8 +157,8 @@ export function makeGrpcRetryInterceptor({ retryableDecider, delayFunction }: Gr
147157
};
148158

149159
const onReceiveStatus = (status: StatusObject) => {
150-
if (retryableDecider(attempt, status)) {
151-
setTimeout(retry, delayFunction(attempt, status));
160+
if (retryOptions.retryableDecider(attempt, status)) {
161+
setTimeout(retry, retryOptions.delayFunction(attempt, status));
152162
} else {
153163
savedMessageNext(savedReceiveMessage);
154164
// TODO: For reasons that are completely unclear to me, if you pass a handcrafted

0 commit comments

Comments
 (0)