Skip to content

Commit b6dd384

Browse files
feat(client): handle retry-after with a date (#340)
1 parent 1bf84b6 commit b6dd384

File tree

2 files changed

+73
-68
lines changed

2 files changed

+73
-68
lines changed

src/core.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -509,32 +509,37 @@ export abstract class APIClient {
509509
retriesRemaining -= 1;
510510

511511
// About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
512-
//
513-
// TODO: we may want to handle the case where the header is using the http-date syntax: "Retry-After: <http-date>".
514-
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax for details.
515-
const retryAfter = parseInt(responseHeaders?.['retry-after'] || '');
512+
let timeoutMillis: number | undefined;
513+
const retryAfterHeader = responseHeaders?.['retry-after'];
514+
if (retryAfterHeader) {
515+
const timeoutSeconds = parseInt(retryAfterHeader);
516+
if (!Number.isNaN(timeoutSeconds)) {
517+
timeoutMillis = timeoutSeconds * 1000;
518+
} else {
519+
timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
520+
}
521+
}
516522

517-
const maxRetries = options.maxRetries ?? this.maxRetries;
518-
const timeout = this.calculateRetryTimeoutSeconds(retriesRemaining, retryAfter, maxRetries) * 1000;
519-
await sleep(timeout);
523+
// If the API asks us to wait a certain amount of time (and it's a reasonable amount),
524+
// just do what it says, but otherwise calculate a default
525+
if (
526+
!timeoutMillis ||
527+
!Number.isInteger(timeoutMillis) ||
528+
timeoutMillis <= 0 ||
529+
timeoutMillis > 60 * 1000
530+
) {
531+
const maxRetries = options.maxRetries ?? this.maxRetries;
532+
timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
533+
}
534+
await sleep(timeoutMillis);
520535

521536
return this.makeRequest(options, retriesRemaining);
522537
}
523538

524-
private calculateRetryTimeoutSeconds(
525-
retriesRemaining: number,
526-
retryAfter: number,
527-
maxRetries: number,
528-
): number {
539+
private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number {
529540
const initialRetryDelay = 0.5;
530541
const maxRetryDelay = 2;
531542

532-
// If the API asks us to wait a certain amount of time (and it's a reasonable amount),
533-
// just do what it says.
534-
if (Number.isInteger(retryAfter) && retryAfter <= 60) {
535-
return retryAfter;
536-
}
537-
538543
const numRetries = maxRetries - retriesRemaining;
539544

540545
// Apply exponential backoff, but not more than the max.
@@ -543,7 +548,7 @@ export abstract class APIClient {
543548
// Apply some jitter, plus-or-minus half a second.
544549
const jitter = Math.random() - 0.5;
545550

546-
return sleepSeconds + jitter;
551+
return (sleepSeconds + jitter) * 1000;
547552
}
548553

549554
private getUserAgent(): string {

yarn.lock

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -905,15 +905,15 @@
905905
"@types/yargs-parser" "*"
906906

907907
"@typescript-eslint/eslint-plugin@^6.7.0":
908-
version "6.7.2"
909-
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz#f18cc75c9cceac8080a9dc2e7d166008c5207b9f"
910-
integrity sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==
908+
version "6.7.3"
909+
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz#d98046e9f7102d49a93d944d413c6055c47fafd7"
910+
integrity sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==
911911
dependencies:
912912
"@eslint-community/regexpp" "^4.5.1"
913-
"@typescript-eslint/scope-manager" "6.7.2"
914-
"@typescript-eslint/type-utils" "6.7.2"
915-
"@typescript-eslint/utils" "6.7.2"
916-
"@typescript-eslint/visitor-keys" "6.7.2"
913+
"@typescript-eslint/scope-manager" "6.7.3"
914+
"@typescript-eslint/type-utils" "6.7.3"
915+
"@typescript-eslint/utils" "6.7.3"
916+
"@typescript-eslint/visitor-keys" "6.7.3"
917917
debug "^4.3.4"
918918
graphemer "^1.4.0"
919919
ignore "^5.2.4"
@@ -922,31 +922,31 @@
922922
ts-api-utils "^1.0.1"
923923

924924
"@typescript-eslint/parser@^6.7.0":
925-
version "6.7.2"
926-
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.2.tgz#e0ae93771441b9518e67d0660c79e3a105497af4"
927-
integrity sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==
928-
dependencies:
929-
"@typescript-eslint/scope-manager" "6.7.2"
930-
"@typescript-eslint/types" "6.7.2"
931-
"@typescript-eslint/typescript-estree" "6.7.2"
932-
"@typescript-eslint/visitor-keys" "6.7.2"
925+
version "6.7.3"
926+
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.3.tgz#aaf40092a32877439e5957e18f2d6a91c82cc2fd"
927+
integrity sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==
928+
dependencies:
929+
"@typescript-eslint/scope-manager" "6.7.3"
930+
"@typescript-eslint/types" "6.7.3"
931+
"@typescript-eslint/typescript-estree" "6.7.3"
932+
"@typescript-eslint/visitor-keys" "6.7.3"
933933
debug "^4.3.4"
934934

935-
"@typescript-eslint/[email protected].2":
936-
version "6.7.2"
937-
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz#cf59a2095d2f894770c94be489648ad1c78dc689"
938-
integrity sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==
935+
"@typescript-eslint/[email protected].3":
936+
version "6.7.3"
937+
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz#07e5709c9bdae3eaf216947433ef97b3b8b7d755"
938+
integrity sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==
939939
dependencies:
940-
"@typescript-eslint/types" "6.7.2"
941-
"@typescript-eslint/visitor-keys" "6.7.2"
940+
"@typescript-eslint/types" "6.7.3"
941+
"@typescript-eslint/visitor-keys" "6.7.3"
942942

943-
"@typescript-eslint/[email protected].2":
944-
version "6.7.2"
945-
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz#ed921c9db87d72fa2939fee242d700561454f367"
946-
integrity sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==
943+
"@typescript-eslint/[email protected].3":
944+
version "6.7.3"
945+
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz#c2c165c135dda68a5e70074ade183f5ad68f3400"
946+
integrity sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==
947947
dependencies:
948-
"@typescript-eslint/typescript-estree" "6.7.2"
949-
"@typescript-eslint/utils" "6.7.2"
948+
"@typescript-eslint/typescript-estree" "6.7.3"
949+
"@typescript-eslint/utils" "6.7.3"
950950
debug "^4.3.4"
951951
ts-api-utils "^1.0.1"
952952

@@ -955,10 +955,10 @@
955955
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.45.0.tgz#794760b9037ee4154c09549ef5a96599621109c5"
956956
integrity sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==
957957

958-
"@typescript-eslint/[email protected].2":
959-
version "6.7.2"
960-
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.2.tgz#75a615a6dbeca09cafd102fe7f465da1d8a3c066"
961-
integrity sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==
958+
"@typescript-eslint/[email protected].3":
959+
version "6.7.3"
960+
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.3.tgz#0402b5628a63f24f2dc9d4a678e9a92cc50ea3e9"
961+
integrity sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==
962962

963963
"@typescript-eslint/[email protected]":
964964
version "5.45.0"
@@ -973,30 +973,30 @@
973973
semver "^7.3.7"
974974
tsutils "^3.21.0"
975975

976-
"@typescript-eslint/[email protected].2":
977-
version "6.7.2"
978-
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz#ce5883c23b581a5caf878af641e49dd0349238c7"
979-
integrity sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==
976+
"@typescript-eslint/[email protected].3":
977+
version "6.7.3"
978+
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz#ec5bb7ab4d3566818abaf0e4a8fa1958561b7279"
979+
integrity sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==
980980
dependencies:
981-
"@typescript-eslint/types" "6.7.2"
982-
"@typescript-eslint/visitor-keys" "6.7.2"
981+
"@typescript-eslint/types" "6.7.3"
982+
"@typescript-eslint/visitor-keys" "6.7.3"
983983
debug "^4.3.4"
984984
globby "^11.1.0"
985985
is-glob "^4.0.3"
986986
semver "^7.5.4"
987987
ts-api-utils "^1.0.1"
988988

989-
"@typescript-eslint/[email protected].2":
990-
version "6.7.2"
991-
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.2.tgz#b9ef0da6f04932167a9222cb4ac59cb187165ebf"
992-
integrity sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==
989+
"@typescript-eslint/[email protected].3":
990+
version "6.7.3"
991+
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.3.tgz#96c655816c373135b07282d67407cb577f62e143"
992+
integrity sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==
993993
dependencies:
994994
"@eslint-community/eslint-utils" "^4.4.0"
995995
"@types/json-schema" "^7.0.12"
996996
"@types/semver" "^7.5.0"
997-
"@typescript-eslint/scope-manager" "6.7.2"
998-
"@typescript-eslint/types" "6.7.2"
999-
"@typescript-eslint/typescript-estree" "6.7.2"
997+
"@typescript-eslint/scope-manager" "6.7.3"
998+
"@typescript-eslint/types" "6.7.3"
999+
"@typescript-eslint/typescript-estree" "6.7.3"
10001000
semver "^7.5.4"
10011001

10021002
"@typescript-eslint/[email protected]":
@@ -1007,12 +1007,12 @@
10071007
"@typescript-eslint/types" "5.45.0"
10081008
eslint-visitor-keys "^3.3.0"
10091009

1010-
"@typescript-eslint/[email protected].2":
1011-
version "6.7.2"
1012-
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz#4cb2bd786f1f459731b0ad1584c9f73e1c7a4d5c"
1013-
integrity sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==
1010+
"@typescript-eslint/[email protected].3":
1011+
version "6.7.3"
1012+
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz#83809631ca12909bd2083558d2f93f5747deebb2"
1013+
integrity sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==
10141014
dependencies:
1015-
"@typescript-eslint/types" "6.7.2"
1015+
"@typescript-eslint/types" "6.7.3"
10161016
eslint-visitor-keys "^3.4.1"
10171017

10181018
abort-controller@^3.0.0:

0 commit comments

Comments
 (0)