@distilled.cloud/core 0.16.2 → 0.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.d.ts +52 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +29 -26
- package/lib/client.js.map +1 -1
- package/lib/errors.d.ts +28 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +46 -5
- package/lib/errors.js.map +1 -1
- package/lib/retry-after.d.ts +63 -0
- package/lib/retry-after.d.ts.map +1 -0
- package/lib/retry-after.js +112 -0
- package/lib/retry-after.js.map +1 -0
- package/lib/retry.d.ts +61 -25
- package/lib/retry.d.ts.map +1 -1
- package/lib/retry.js +125 -32
- package/lib/retry.js.map +1 -1
- package/package.json +6 -1
- package/src/client.ts +65 -29
- package/src/errors.ts +51 -5
- package/src/retry-after.ts +131 -0
- package/src/retry.ts +157 -46
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-provided retry hint parsing.
|
|
3
|
+
*
|
|
4
|
+
* Standardizes parsing of:
|
|
5
|
+
* - `Retry-After` (RFC 7231 §7.1.3): `delay-seconds` (integer) or `HTTP-date`.
|
|
6
|
+
* - `RateLimit` (IETF draft-ietf-httpapi-ratelimit-headers): structured
|
|
7
|
+
* dictionary `r=<remaining>, t=<seconds-until-reset>`.
|
|
8
|
+
*
|
|
9
|
+
* Each SDK's `matchError` calls these helpers and attaches the resulting
|
|
10
|
+
* `Duration` to retryable errors via the optional `retryAfter` field, where
|
|
11
|
+
* the retry policy will honor it with precedence over the default backoff.
|
|
12
|
+
*
|
|
13
|
+
* Services that use bespoke headers or body fields are expected to do their
|
|
14
|
+
* own parsing in the SDK's `matchError`, optionally falling back to these
|
|
15
|
+
* helpers for the standard cases.
|
|
16
|
+
*/
|
|
17
|
+
import * as Duration from "effect/Duration";
|
|
18
|
+
import { RETRYABLE_HTTP_STATUSES } from "./errors.js";
|
|
19
|
+
/**
|
|
20
|
+
* Parse the standard `Retry-After` HTTP header per RFC 7231 §7.1.3.
|
|
21
|
+
*
|
|
22
|
+
* Accepts either a non-negative integer number of seconds (the common case)
|
|
23
|
+
* or an HTTP-date. HTTP-dates in the past produce a zero duration.
|
|
24
|
+
*
|
|
25
|
+
* Returns `undefined` when the header is missing or unparseable.
|
|
26
|
+
*/
|
|
27
|
+
export const parseRetryAfter = (headers) => {
|
|
28
|
+
const raw = headers?.["retry-after"];
|
|
29
|
+
if (!raw)
|
|
30
|
+
return undefined;
|
|
31
|
+
const trimmed = raw.trim();
|
|
32
|
+
if (trimmed.length === 0)
|
|
33
|
+
return undefined;
|
|
34
|
+
// delay-seconds: 1*DIGIT (non-negative decimal integer per RFC).
|
|
35
|
+
if (/^\d+$/.test(trimmed)) {
|
|
36
|
+
const seconds = Number(trimmed);
|
|
37
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
38
|
+
return Duration.seconds(seconds);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Reject anything that *looks* numeric but isn't a valid delay-seconds.
|
|
42
|
+
// Without this, `Date.parse("-5")` happens to return 0 on some engines and
|
|
43
|
+
// would silently yield a zero-duration instead of the expected undefined.
|
|
44
|
+
if (/^[-+]?\d+(?:\.\d+)?$/.test(trimmed))
|
|
45
|
+
return undefined;
|
|
46
|
+
// HTTP-date: try Date.parse, which handles RFC 1123 / RFC 850 / asctime.
|
|
47
|
+
const ts = Date.parse(trimmed);
|
|
48
|
+
if (!Number.isNaN(ts)) {
|
|
49
|
+
const ms = Math.max(0, ts - Date.now());
|
|
50
|
+
return Duration.millis(ms);
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Parse the IETF `RateLimit` structured header.
|
|
56
|
+
*
|
|
57
|
+
* Examples:
|
|
58
|
+
* `RateLimit: limit=100, remaining=0, reset=30` (older draft)
|
|
59
|
+
* `RateLimit: "default";r=0;t=30` (newer draft)
|
|
60
|
+
* `RateLimit: r=0, t=30` (compact form)
|
|
61
|
+
*
|
|
62
|
+
* Returns the `t` (seconds until reset) value as a Duration, but only when
|
|
63
|
+
* `r` (remaining quota) is present and equals `0` — i.e., we're actually
|
|
64
|
+
* rate-limited right now. Returns `undefined` otherwise.
|
|
65
|
+
*/
|
|
66
|
+
export const parseRatelimit = (headers) => {
|
|
67
|
+
const raw = headers?.["ratelimit"];
|
|
68
|
+
if (!raw)
|
|
69
|
+
return undefined;
|
|
70
|
+
let remaining;
|
|
71
|
+
let reset;
|
|
72
|
+
// Tokenize on commas and semicolons; tolerate `key=value` and `key =value`.
|
|
73
|
+
for (const piece of raw.split(/[,;]/)) {
|
|
74
|
+
const eq = piece.indexOf("=");
|
|
75
|
+
if (eq < 0)
|
|
76
|
+
continue;
|
|
77
|
+
const key = piece.slice(0, eq).trim().toLowerCase();
|
|
78
|
+
const value = piece.slice(eq + 1).trim();
|
|
79
|
+
const num = Number(value);
|
|
80
|
+
if (!Number.isFinite(num))
|
|
81
|
+
continue;
|
|
82
|
+
if (key === "r" || key === "remaining")
|
|
83
|
+
remaining = num;
|
|
84
|
+
else if (key === "t" || key === "reset")
|
|
85
|
+
reset = num;
|
|
86
|
+
}
|
|
87
|
+
if (remaining !== undefined && remaining > 0)
|
|
88
|
+
return undefined;
|
|
89
|
+
if (reset === undefined || reset < 0)
|
|
90
|
+
return undefined;
|
|
91
|
+
return Duration.seconds(reset);
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Convenience: try `Retry-After` first, then `RateLimit`. Returns the first
|
|
95
|
+
* successful parse, or `undefined` if neither header yields a usable value.
|
|
96
|
+
*/
|
|
97
|
+
export const parseServerRetryHint = (headers) => parseRetryAfter(headers) ?? parseRatelimit(headers);
|
|
98
|
+
/**
|
|
99
|
+
* Status-gated variant of {@link parseServerRetryHint}. Returns `undefined`
|
|
100
|
+
* unless `status` is one whose error class actually declares a `retryAfter`
|
|
101
|
+
* field (see `RETRYABLE_HTTP_STATUSES`). Use this in `matchError` when you
|
|
102
|
+
* dispatch off a generic `HTTP_STATUS_MAP` lookup that includes both
|
|
103
|
+
* retryable (429/5xx/423) and non-retryable (4xx) classes — it prevents
|
|
104
|
+
* stale `retryAfter` properties from being attached to errors like
|
|
105
|
+
* `BadRequest` or `NotFound` (which would otherwise leak into JSON output).
|
|
106
|
+
*/
|
|
107
|
+
export const parseRetryAfterForStatus = (status, headers) => {
|
|
108
|
+
if (!RETRYABLE_HTTP_STATUSES.has(status))
|
|
109
|
+
return undefined;
|
|
110
|
+
return parseServerRetryHint(headers);
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=retry-after.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-after.js","sourceRoot":"","sources":["../src/retry-after.ts"],"names":[],"mappings":"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"}
|
package/lib/retry.d.ts
CHANGED
|
@@ -2,22 +2,13 @@
|
|
|
2
2
|
* Retry Policy System
|
|
3
3
|
*
|
|
4
4
|
* Provides configurable retry policies for API operations.
|
|
5
|
-
* Each SDK creates its own Retry
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* import * as Retry from "@distilled.cloud/core/retry";
|
|
11
|
-
*
|
|
12
|
-
* // Use the default retry policy
|
|
13
|
-
* myEffect.pipe(Retry.policy(myRetryService, Retry.makeDefault()))
|
|
14
|
-
*
|
|
15
|
-
* // Disable retries
|
|
16
|
-
* myEffect.pipe(Retry.none(myRetryService))
|
|
17
|
-
* ```
|
|
5
|
+
* Each SDK creates its own `Retry` Context.Service tag (via
|
|
6
|
+
* `makeRetryService`) and threads it into `makeAPI({ retry: <SDK>.Retry })`
|
|
7
|
+
* so that callers can install a blanket retry policy at the layer level
|
|
8
|
+
* for that SDK without wrapping every call with `Effect.retry`.
|
|
18
9
|
*/
|
|
19
10
|
import * as Duration from "effect/Duration";
|
|
20
|
-
import * as
|
|
11
|
+
import * as Layer from "effect/Layer";
|
|
21
12
|
import * as Ref from "effect/Ref";
|
|
22
13
|
import * as Schedule from "effect/Schedule";
|
|
23
14
|
import * as Context from "effect/Context";
|
|
@@ -45,23 +36,17 @@ export type Factory = (lastError: Ref.Ref<unknown>) => Options;
|
|
|
45
36
|
export type Policy = Options | Factory;
|
|
46
37
|
/**
|
|
47
38
|
* Create a typed Retry service class for an SDK.
|
|
48
|
-
* Each SDK
|
|
39
|
+
* Each SDK creates its own Retry service using this factory; the SDK's
|
|
40
|
+
* client wraps `makeAPI` with `retry: <SDK>.Retry` so the policy applies
|
|
41
|
+
* to every API call below it.
|
|
49
42
|
*
|
|
50
43
|
* @example
|
|
51
44
|
* ```ts
|
|
52
|
-
* //
|
|
45
|
+
* // packages/<sdk>/src/retry.ts
|
|
53
46
|
* export class Retry extends makeRetryService("PlanetScaleRetry") {}
|
|
54
47
|
* ```
|
|
55
48
|
*/
|
|
56
49
|
export declare const makeRetryService: (name: string) => Context.ServiceClass<any, string, Policy>;
|
|
57
|
-
/**
|
|
58
|
-
* Provides a custom retry policy for API calls.
|
|
59
|
-
*/
|
|
60
|
-
export declare const policy: (Service: any, optionsOrFactory: Policy) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, unknown, unknown>;
|
|
61
|
-
/**
|
|
62
|
-
* Disables all automatic retries.
|
|
63
|
-
*/
|
|
64
|
-
export declare const none: (Service: any) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, unknown, unknown>;
|
|
65
50
|
/**
|
|
66
51
|
* Custom jittered schedule helper.
|
|
67
52
|
* Adds random jitter between 0-50ms to avoid thundering herd.
|
|
@@ -71,21 +56,70 @@ export declare const jittered: <Input, Error, Env>(self: Schedule.Schedule<unkno
|
|
|
71
56
|
* Cap delay at a maximum duration.
|
|
72
57
|
*/
|
|
73
58
|
export declare const capped: (max: Duration.Duration) => <Input, Error, Env>(self: Schedule.Schedule<Duration.Duration, Input, Error, Env>) => Schedule.Schedule<Duration.Duration, Input, Error, Env>;
|
|
59
|
+
/**
|
|
60
|
+
* Default cap (milliseconds) on how long we'll honor a server-provided
|
|
61
|
+
* `Retry-After` / `RateLimit` hint. A misbehaving server can otherwise park
|
|
62
|
+
* us forever.
|
|
63
|
+
*/
|
|
64
|
+
export declare const DEFAULT_SERVER_RETRY_HINT_CAP_MS = 60000;
|
|
65
|
+
/**
|
|
66
|
+
* Optional override for the server-hint cap, in milliseconds. When provided
|
|
67
|
+
* via `Layer.succeed(ServerRetryHintCapMs, n)`, that value wins over the
|
|
68
|
+
* environment.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* Effect.retry(op, policy).pipe(
|
|
73
|
+
* Effect.provide(serverRetryHintCapLayer(120_000)),
|
|
74
|
+
* )
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare const ServerRetryHintCapMs: Context.Service<number, number>;
|
|
78
|
+
/**
|
|
79
|
+
* Layer that pins the server `retryAfter` cap to a fixed value (milliseconds).
|
|
80
|
+
*/
|
|
81
|
+
export declare const serverRetryHintCapLayer: (capMs: number) => Layer.Layer<number, never, never>;
|
|
82
|
+
/**
|
|
83
|
+
* Effective cap when neither {@link ServerRetryHintCapMs} nor
|
|
84
|
+
* `DISTILLED_SERVER_RETRY_HINT_CAP_MS` is set: {@link DEFAULT_SERVER_RETRY_HINT_CAP_MS}.
|
|
85
|
+
*
|
|
86
|
+
* Reads `process.env.DISTILLED_SERVER_RETRY_HINT_CAP_MS` when present (must be
|
|
87
|
+
* a non-negative finite integer; invalid values are ignored). Undefined
|
|
88
|
+
* `process` (some edge runtimes) falls back to the default.
|
|
89
|
+
*/
|
|
90
|
+
export declare const readServerRetryHintCapMsFromEnv: () => number;
|
|
74
91
|
/**
|
|
75
92
|
* Creates the default retry policy.
|
|
76
93
|
*
|
|
77
94
|
* This policy:
|
|
78
95
|
* - Retries transient errors (throttling, server, network, locked errors)
|
|
79
|
-
* -
|
|
96
|
+
* - Honors `error.retryAfter` (server-provided hint) with precedence, capped
|
|
97
|
+
* by {@link DEFAULT_SERVER_RETRY_HINT_CAP_MS} by default; override with
|
|
98
|
+
* `DISTILLED_SERVER_RETRY_HINT_CAP_MS` or {@link ServerRetryHintCapMs}
|
|
99
|
+
* - Otherwise uses exponential backoff starting at 100ms with a factor of 2
|
|
80
100
|
* - Ensures at least 500ms delay for throttling errors
|
|
81
101
|
* - Limits to 5 retry attempts
|
|
82
102
|
* - Applies jitter to avoid thundering herd
|
|
83
103
|
*/
|
|
84
104
|
export declare const makeDefault: Factory;
|
|
105
|
+
/**
|
|
106
|
+
* Factory for the throttling-only retry policy. Honors server hints when
|
|
107
|
+
* present so callers using `<SDK>.Retry.throttling` get correct backoff.
|
|
108
|
+
*/
|
|
109
|
+
export declare const throttlingFactory: Factory;
|
|
85
110
|
/**
|
|
86
111
|
* Retry options that retries all throttling errors indefinitely.
|
|
112
|
+
*
|
|
113
|
+
* Note: prefer {@link throttlingFactory} when you want server-hint honoring.
|
|
114
|
+
* This static `Options` form does not have access to `lastError` and so
|
|
115
|
+
* cannot read `error.retryAfter`.
|
|
87
116
|
*/
|
|
88
117
|
export declare const throttlingOptions: Options;
|
|
118
|
+
/**
|
|
119
|
+
* Factory for the transient retry policy. Honors server hints when present
|
|
120
|
+
* so callers using `<SDK>.Retry.transient` get correct backoff.
|
|
121
|
+
*/
|
|
122
|
+
export declare const transientFactory: Factory;
|
|
89
123
|
/**
|
|
90
124
|
* Retry options that retries all transient errors indefinitely.
|
|
91
125
|
*
|
|
@@ -94,6 +128,8 @@ export declare const throttlingOptions: Options;
|
|
|
94
128
|
* 2. Server errors
|
|
95
129
|
* 3. Network errors
|
|
96
130
|
* 4. Locked errors (423)
|
|
131
|
+
*
|
|
132
|
+
* Note: prefer {@link transientFactory} when you want server-hint honoring.
|
|
97
133
|
*/
|
|
98
134
|
export declare const transientOptions: Options;
|
|
99
135
|
//# sourceMappingURL=retry.d.ts.map
|
package/lib/retry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAG5C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAO1C;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAC7C;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CAChD;AAED;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAMvC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,SAAU,MAAM,8CACP,CAAC;AAMvC;;;GAGG;AACH,eAAO,MAAM,QAAQ,2HAEpB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,MAAM,QAAS,QAAQ,CAAC,QAAQ,kJAK1C,CAAC;AAMJ;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAIvD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,iCAEhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,UAAW,MAAM,sCACT,CAAC;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,QAAO,MASlD,CAAC;AAwDF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,EAAE,OAaxB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAQ9B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAO/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAQ7B,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAO9B,CAAC"}
|
package/lib/retry.js
CHANGED
|
@@ -2,24 +2,16 @@
|
|
|
2
2
|
* Retry Policy System
|
|
3
3
|
*
|
|
4
4
|
* Provides configurable retry policies for API operations.
|
|
5
|
-
* Each SDK creates its own Retry
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* import * as Retry from "@distilled.cloud/core/retry";
|
|
11
|
-
*
|
|
12
|
-
* // Use the default retry policy
|
|
13
|
-
* myEffect.pipe(Retry.policy(myRetryService, Retry.makeDefault()))
|
|
14
|
-
*
|
|
15
|
-
* // Disable retries
|
|
16
|
-
* myEffect.pipe(Retry.none(myRetryService))
|
|
17
|
-
* ```
|
|
5
|
+
* Each SDK creates its own `Retry` Context.Service tag (via
|
|
6
|
+
* `makeRetryService`) and threads it into `makeAPI({ retry: <SDK>.Retry })`
|
|
7
|
+
* so that callers can install a blanket retry policy at the layer level
|
|
8
|
+
* for that SDK without wrapping every call with `Effect.retry`.
|
|
18
9
|
*/
|
|
19
10
|
import * as Duration from "effect/Duration";
|
|
20
11
|
import * as Effect from "effect/Effect";
|
|
21
12
|
import { pipe } from "effect/Function";
|
|
22
13
|
import * as Layer from "effect/Layer";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
23
15
|
import * as Ref from "effect/Ref";
|
|
24
16
|
import * as Schedule from "effect/Schedule";
|
|
25
17
|
import * as Context from "effect/Context";
|
|
@@ -29,23 +21,17 @@ import { isThrottling, isTransientError } from "./category.js";
|
|
|
29
21
|
// ============================================================================
|
|
30
22
|
/**
|
|
31
23
|
* Create a typed Retry service class for an SDK.
|
|
32
|
-
* Each SDK
|
|
24
|
+
* Each SDK creates its own Retry service using this factory; the SDK's
|
|
25
|
+
* client wraps `makeAPI` with `retry: <SDK>.Retry` so the policy applies
|
|
26
|
+
* to every API call below it.
|
|
33
27
|
*
|
|
34
28
|
* @example
|
|
35
29
|
* ```ts
|
|
36
|
-
* //
|
|
30
|
+
* // packages/<sdk>/src/retry.ts
|
|
37
31
|
* export class Retry extends makeRetryService("PlanetScaleRetry") {}
|
|
38
32
|
* ```
|
|
39
33
|
*/
|
|
40
34
|
export const makeRetryService = (name) => Context.Service()(name);
|
|
41
|
-
/**
|
|
42
|
-
* Provides a custom retry policy for API calls.
|
|
43
|
-
*/
|
|
44
|
-
export const policy = (Service, optionsOrFactory) => (effect) => Effect.provide(effect, Layer.succeed(Service, optionsOrFactory));
|
|
45
|
-
/**
|
|
46
|
-
* Disables all automatic retries.
|
|
47
|
-
*/
|
|
48
|
-
export const none = (Service) => (effect) => Effect.provide(effect, Layer.succeed(Service, { while: () => false }));
|
|
49
35
|
// ============================================================================
|
|
50
36
|
// Retry Schedule Utilities
|
|
51
37
|
// ============================================================================
|
|
@@ -59,6 +45,91 @@ export const jittered = Schedule.addDelay(() => Effect.succeed(Duration.millis(M
|
|
|
59
45
|
*/
|
|
60
46
|
export const capped = (max) => Schedule.modifyDelay((duration) => Effect.succeed(Duration.isGreaterThan(duration, max) ? Duration.millis(5000) : duration));
|
|
61
47
|
// ============================================================================
|
|
48
|
+
// Server Hint Helpers
|
|
49
|
+
// ============================================================================
|
|
50
|
+
/**
|
|
51
|
+
* Default cap (milliseconds) on how long we'll honor a server-provided
|
|
52
|
+
* `Retry-After` / `RateLimit` hint. A misbehaving server can otherwise park
|
|
53
|
+
* us forever.
|
|
54
|
+
*/
|
|
55
|
+
export const DEFAULT_SERVER_RETRY_HINT_CAP_MS = 60_000;
|
|
56
|
+
const ENV_SERVER_RETRY_HINT_CAP_MS = "DISTILLED_SERVER_RETRY_HINT_CAP_MS";
|
|
57
|
+
/**
|
|
58
|
+
* Optional override for the server-hint cap, in milliseconds. When provided
|
|
59
|
+
* via `Layer.succeed(ServerRetryHintCapMs, n)`, that value wins over the
|
|
60
|
+
* environment.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* Effect.retry(op, policy).pipe(
|
|
65
|
+
* Effect.provide(serverRetryHintCapLayer(120_000)),
|
|
66
|
+
* )
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export const ServerRetryHintCapMs = Context.Service("@distilled.cloud/core/ServerRetryHintCapMs");
|
|
70
|
+
/**
|
|
71
|
+
* Layer that pins the server `retryAfter` cap to a fixed value (milliseconds).
|
|
72
|
+
*/
|
|
73
|
+
export const serverRetryHintCapLayer = (capMs) => Layer.succeed(ServerRetryHintCapMs, capMs);
|
|
74
|
+
/**
|
|
75
|
+
* Effective cap when neither {@link ServerRetryHintCapMs} nor
|
|
76
|
+
* `DISTILLED_SERVER_RETRY_HINT_CAP_MS` is set: {@link DEFAULT_SERVER_RETRY_HINT_CAP_MS}.
|
|
77
|
+
*
|
|
78
|
+
* Reads `process.env.DISTILLED_SERVER_RETRY_HINT_CAP_MS` when present (must be
|
|
79
|
+
* a non-negative finite integer; invalid values are ignored). Undefined
|
|
80
|
+
* `process` (some edge runtimes) falls back to the default.
|
|
81
|
+
*/
|
|
82
|
+
export const readServerRetryHintCapMsFromEnv = () => {
|
|
83
|
+
if (typeof process === "undefined" || process.env === undefined) {
|
|
84
|
+
return DEFAULT_SERVER_RETRY_HINT_CAP_MS;
|
|
85
|
+
}
|
|
86
|
+
const raw = process.env[ENV_SERVER_RETRY_HINT_CAP_MS];
|
|
87
|
+
if (raw === undefined || raw === "")
|
|
88
|
+
return DEFAULT_SERVER_RETRY_HINT_CAP_MS;
|
|
89
|
+
const n = Number(raw);
|
|
90
|
+
if (!Number.isFinite(n) || n < 0)
|
|
91
|
+
return DEFAULT_SERVER_RETRY_HINT_CAP_MS;
|
|
92
|
+
return Math.trunc(n);
|
|
93
|
+
};
|
|
94
|
+
const resolveServerRetryHintCapMs = () => Effect.gen(function* () {
|
|
95
|
+
const fromLayer = yield* Effect.serviceOption(ServerRetryHintCapMs);
|
|
96
|
+
return Option.match(fromLayer, {
|
|
97
|
+
onNone: () => readServerRetryHintCapMsFromEnv(),
|
|
98
|
+
onSome: (n) => Number.isFinite(n) && n >= 0
|
|
99
|
+
? Math.trunc(n)
|
|
100
|
+
: readServerRetryHintCapMsFromEnv(),
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
/**
|
|
104
|
+
* Extract a server-provided retry hint (in milliseconds) from an error's
|
|
105
|
+
* optional `retryAfter` field, capped by the effective server-hint cap
|
|
106
|
+
* (see {@link ServerRetryHintCapMs} and {@link readServerRetryHintCapMsFromEnv}).
|
|
107
|
+
*
|
|
108
|
+
* Returns `undefined` when the error doesn't carry a hint.
|
|
109
|
+
*/
|
|
110
|
+
const serverHintMillis = (error, capMs) => {
|
|
111
|
+
const hint = error
|
|
112
|
+
?.retryAfter;
|
|
113
|
+
if (!Duration.isDuration(hint))
|
|
114
|
+
return undefined;
|
|
115
|
+
return Math.min(Duration.toMillis(hint), capMs);
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Schedule modifier that honors `error.retryAfter` (set by the SDK's
|
|
119
|
+
* `matchError` from `Retry-After` / `RateLimit` headers) with precedence
|
|
120
|
+
* over the input delay. Falls back to the original delay when no hint is
|
|
121
|
+
* present.
|
|
122
|
+
*/
|
|
123
|
+
const honorServerHint = (lastError, baseline) => Schedule.modifyDelay(Effect.fnUntraced(function* (duration) {
|
|
124
|
+
const capMs = yield* resolveServerRetryHintCapMs();
|
|
125
|
+
const error = yield* Ref.get(lastError);
|
|
126
|
+
const hint = serverHintMillis(error, capMs);
|
|
127
|
+
if (hint !== undefined)
|
|
128
|
+
return hint;
|
|
129
|
+
const adjusted = baseline ? baseline(duration, error) : duration;
|
|
130
|
+
return Duration.toMillis(adjusted);
|
|
131
|
+
}));
|
|
132
|
+
// ============================================================================
|
|
62
133
|
// Default Retry Policies
|
|
63
134
|
// ============================================================================
|
|
64
135
|
/**
|
|
@@ -66,30 +137,50 @@ export const capped = (max) => Schedule.modifyDelay((duration) => Effect.succeed
|
|
|
66
137
|
*
|
|
67
138
|
* This policy:
|
|
68
139
|
* - Retries transient errors (throttling, server, network, locked errors)
|
|
69
|
-
* -
|
|
140
|
+
* - Honors `error.retryAfter` (server-provided hint) with precedence, capped
|
|
141
|
+
* by {@link DEFAULT_SERVER_RETRY_HINT_CAP_MS} by default; override with
|
|
142
|
+
* `DISTILLED_SERVER_RETRY_HINT_CAP_MS` or {@link ServerRetryHintCapMs}
|
|
143
|
+
* - Otherwise uses exponential backoff starting at 100ms with a factor of 2
|
|
70
144
|
* - Ensures at least 500ms delay for throttling errors
|
|
71
145
|
* - Limits to 5 retry attempts
|
|
72
146
|
* - Applies jitter to avoid thundering herd
|
|
73
147
|
*/
|
|
74
148
|
export const makeDefault = (lastError) => ({
|
|
75
149
|
while: (error) => isTransientError(error),
|
|
76
|
-
schedule: pipe(Schedule.exponential(100, 2),
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (Duration.toMillis(duration) < 500) {
|
|
80
|
-
return Duration.toMillis(Duration.millis(500));
|
|
81
|
-
}
|
|
150
|
+
schedule: pipe(Schedule.exponential(100, 2), honorServerHint(lastError, (duration, error) => {
|
|
151
|
+
if (isThrottling(error) && Duration.toMillis(duration) < 500) {
|
|
152
|
+
return Duration.millis(500);
|
|
82
153
|
}
|
|
83
|
-
return
|
|
84
|
-
})
|
|
154
|
+
return duration;
|
|
155
|
+
}), Schedule.both(Schedule.recurs(5)), jittered),
|
|
156
|
+
});
|
|
157
|
+
/**
|
|
158
|
+
* Factory for the throttling-only retry policy. Honors server hints when
|
|
159
|
+
* present so callers using `<SDK>.Retry.throttling` get correct backoff.
|
|
160
|
+
*/
|
|
161
|
+
export const throttlingFactory = (lastError) => ({
|
|
162
|
+
while: (error) => isThrottling(error),
|
|
163
|
+
schedule: pipe(Schedule.exponential(1000, 2), honorServerHint(lastError), capped(Duration.seconds(5)), jittered),
|
|
85
164
|
});
|
|
86
165
|
/**
|
|
87
166
|
* Retry options that retries all throttling errors indefinitely.
|
|
167
|
+
*
|
|
168
|
+
* Note: prefer {@link throttlingFactory} when you want server-hint honoring.
|
|
169
|
+
* This static `Options` form does not have access to `lastError` and so
|
|
170
|
+
* cannot read `error.retryAfter`.
|
|
88
171
|
*/
|
|
89
172
|
export const throttlingOptions = {
|
|
90
173
|
while: (error) => isThrottling(error),
|
|
91
174
|
schedule: pipe(Schedule.exponential(1000, 2), capped(Duration.seconds(5)), jittered),
|
|
92
175
|
};
|
|
176
|
+
/**
|
|
177
|
+
* Factory for the transient retry policy. Honors server hints when present
|
|
178
|
+
* so callers using `<SDK>.Retry.transient` get correct backoff.
|
|
179
|
+
*/
|
|
180
|
+
export const transientFactory = (lastError) => ({
|
|
181
|
+
while: isTransientError,
|
|
182
|
+
schedule: pipe(Schedule.exponential(1000, 2), honorServerHint(lastError), capped(Duration.seconds(5)), jittered),
|
|
183
|
+
});
|
|
93
184
|
/**
|
|
94
185
|
* Retry options that retries all transient errors indefinitely.
|
|
95
186
|
*
|
|
@@ -98,6 +189,8 @@ export const throttlingOptions = {
|
|
|
98
189
|
* 2. Server errors
|
|
99
190
|
* 3. Network errors
|
|
100
191
|
* 4. Locked errors (423)
|
|
192
|
+
*
|
|
193
|
+
* Note: prefer {@link transientFactory} when you want server-hint honoring.
|
|
101
194
|
*/
|
|
102
195
|
export const transientOptions = {
|
|
103
196
|
while: isTransientError,
|
package/lib/retry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@distilled.cloud/core",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/alchemy-run/distilled",
|
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
"bun": "./src/retry.ts",
|
|
44
44
|
"default": "./lib/retry.js"
|
|
45
45
|
},
|
|
46
|
+
"./retry-after": {
|
|
47
|
+
"types": "./lib/retry-after.d.ts",
|
|
48
|
+
"bun": "./src/retry-after.ts",
|
|
49
|
+
"default": "./lib/retry-after.js"
|
|
50
|
+
},
|
|
46
51
|
"./sensitive": {
|
|
47
52
|
"types": "./lib/sensitive.d.ts",
|
|
48
53
|
"bun": "./src/sensitive.ts",
|