@cqrs-ddd/pipeline-resilience 0.5.0
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/COMMERCIAL_LICENSE.txt +34 -0
- package/LICENSE +661 -0
- package/README.md +36 -0
- package/dist/errors/resilience-configuration.error.d.ts +13 -0
- package/dist/errors/resilience-configuration.error.d.ts.map +1 -0
- package/dist/errors/resilience-configuration.error.js +19 -0
- package/dist/errors/resilience-configuration.error.js.map +1 -0
- package/dist/errors/resilience-policy-configuration.error.d.ts +12 -0
- package/dist/errors/resilience-policy-configuration.error.d.ts.map +1 -0
- package/dist/errors/resilience-policy-configuration.error.js +17 -0
- package/dist/errors/resilience-policy-configuration.error.js.map +1 -0
- package/dist/helpers/policy-factory.d.ts +34 -0
- package/dist/helpers/policy-factory.d.ts.map +1 -0
- package/dist/helpers/policy-factory.js +189 -0
- package/dist/helpers/policy-factory.js.map +1 -0
- package/dist/helpers/resilience-context.d.ts +38 -0
- package/dist/helpers/resilience-context.d.ts.map +1 -0
- package/dist/helpers/resilience-context.js +45 -0
- package/dist/helpers/resilience-context.js.map +1 -0
- package/dist/helpers/resilience.intent.d.ts +29 -0
- package/dist/helpers/resilience.intent.d.ts.map +1 -0
- package/dist/helpers/resilience.intent.js +21 -0
- package/dist/helpers/resilience.intent.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/resilience-options.interface.d.ts +326 -0
- package/dist/interfaces/resilience-options.interface.d.ts.map +1 -0
- package/dist/interfaces/resilience-options.interface.js +3 -0
- package/dist/interfaces/resilience-options.interface.js.map +1 -0
- package/dist/resilience-policies.d.ts +48 -0
- package/dist/resilience-policies.d.ts.map +1 -0
- package/dist/resilience-policies.js +75 -0
- package/dist/resilience-policies.js.map +1 -0
- package/dist/resilience.behavior.d.ts +64 -0
- package/dist/resilience.behavior.d.ts.map +1 -0
- package/dist/resilience.behavior.js +159 -0
- package/dist/resilience.behavior.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import type { IPolicy } from 'cockatiel';
|
|
2
|
+
/**
|
|
3
|
+
* The resilience layers that can be composed, listed from **outermost**
|
|
4
|
+
* (runs first / wraps everything) to **innermost** (closest to the handler).
|
|
5
|
+
*
|
|
6
|
+
* The default composition order is:
|
|
7
|
+
* `fallback → retry → circuitBreaker → bulkhead → timeout → handler`.
|
|
8
|
+
*/
|
|
9
|
+
export type ResilienceLayer = 'fallback' | 'retry' | 'circuitBreaker' | 'bulkhead' | 'timeout';
|
|
10
|
+
/**
|
|
11
|
+
* The layers {@link ResilienceBehavior} applies around a whole handler.
|
|
12
|
+
* Circuit breaker and fallback belong to a dependency, so they exist only on
|
|
13
|
+
* named policies ({@link ResiliencePolicyOptions}).
|
|
14
|
+
*/
|
|
15
|
+
export type HandlerResilienceLayer = Exclude<ResilienceLayer, 'circuitBreaker' | 'fallback'>;
|
|
16
|
+
/** Jitter strategy used by the exponential backoff generator. */
|
|
17
|
+
export type JitterStrategy = 'decorrelated' | 'none' | 'full' | 'half';
|
|
18
|
+
/** Backoff strategy controlling the delay between retry attempts. */
|
|
19
|
+
export type RetryBackoff =
|
|
20
|
+
/** Wait a fixed `delay` (ms) between every attempt. */
|
|
21
|
+
{
|
|
22
|
+
type: 'constant';
|
|
23
|
+
delay: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decorrelated-jitter exponential backoff (recommended). All fields are
|
|
27
|
+
* optional and fall back to cockatiel's defaults
|
|
28
|
+
* (`initialDelay: 128`, `maxDelay: 30_000`, `exponent: 2`).
|
|
29
|
+
*/
|
|
30
|
+
| {
|
|
31
|
+
type: 'exponential';
|
|
32
|
+
initialDelay?: number;
|
|
33
|
+
maxDelay?: number;
|
|
34
|
+
exponent?: number;
|
|
35
|
+
jitter?: JitterStrategy;
|
|
36
|
+
}
|
|
37
|
+
/** Walk through an explicit list of delays (ms); the last value repeats. */
|
|
38
|
+
| {
|
|
39
|
+
type: 'iterable';
|
|
40
|
+
delays: number[];
|
|
41
|
+
};
|
|
42
|
+
/** Retry configuration of a named policy: re-runs the call on a handled failure. */
|
|
43
|
+
export interface RetryPolicyOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Maximum number of retry attempts after the initial call (e.g. `3` allows
|
|
46
|
+
* the original execution plus up to three retries), matching Cockatiel's
|
|
47
|
+
* `retry(..., { maxAttempts })` semantics.
|
|
48
|
+
*/
|
|
49
|
+
maxAttempts: number;
|
|
50
|
+
/** Delay strategy between attempts. Defaults to no delay. */
|
|
51
|
+
backoff?: RetryBackoff;
|
|
52
|
+
}
|
|
53
|
+
/** Retry configuration of the behavior — re-runs all downstream pipeline work on a handled failure. */
|
|
54
|
+
export interface RetryOptions extends RetryPolicyOptions {
|
|
55
|
+
/**
|
|
56
|
+
* Explicit acknowledgement that replaying the handler/downstream behaviors is
|
|
57
|
+
* safe. Required for `command` and `event` retries because those request kinds
|
|
58
|
+
* commonly perform side effects.
|
|
59
|
+
*
|
|
60
|
+
* Queries do not require this acknowledgement.
|
|
61
|
+
*
|
|
62
|
+
* Set this only when the operation is genuinely replay-safe — for example the
|
|
63
|
+
* side effect is protected by a downstream idempotency key, transaction, or
|
|
64
|
+
* otherwise repeatable contract. `@cqrs-ddd/pipeline-idempotency` does not make
|
|
65
|
+
* arbitrary external effects exactly-once by itself.
|
|
66
|
+
*
|
|
67
|
+
* @example Replay-safe command retry
|
|
68
|
+
* ```ts
|
|
69
|
+
* @pipeline.wrap({ kind: 'command' }, [ResilienceBehavior, {
|
|
70
|
+
* retry: {
|
|
71
|
+
* maxAttempts: 2,
|
|
72
|
+
* replaySafe: true,
|
|
73
|
+
* backoff: { type: 'exponential', maxDelay: 1_000 },
|
|
74
|
+
* },
|
|
75
|
+
* handle: (error) => error instanceof TransientGatewayError,
|
|
76
|
+
* }])
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
replaySafe?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/** Circuit breaker strategy controlling when the circuit opens. */
|
|
82
|
+
export type BreakerStrategy =
|
|
83
|
+
/** Open after `threshold` consecutive failures. */
|
|
84
|
+
{
|
|
85
|
+
type: 'consecutive';
|
|
86
|
+
threshold: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Open when the failure proportion exceeds `threshold` (0–1) within a
|
|
90
|
+
* rolling `duration` (ms) window. `minimumRps` avoids tripping under low load.
|
|
91
|
+
*/
|
|
92
|
+
| {
|
|
93
|
+
type: 'sampling';
|
|
94
|
+
threshold: number;
|
|
95
|
+
duration: number;
|
|
96
|
+
minimumRps?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Open when the failure proportion exceeds `threshold` (0–1) over the last
|
|
100
|
+
* `size` calls (count-based sliding window).
|
|
101
|
+
*/
|
|
102
|
+
| {
|
|
103
|
+
type: 'count';
|
|
104
|
+
threshold: number;
|
|
105
|
+
size: number;
|
|
106
|
+
minimumNumberOfCalls?: number;
|
|
107
|
+
};
|
|
108
|
+
/** Circuit breaker configuration. */
|
|
109
|
+
export interface CircuitBreakerOptions {
|
|
110
|
+
/**
|
|
111
|
+
* Milliseconds the circuit stays open before allowing a trial (half-open)
|
|
112
|
+
* call through.
|
|
113
|
+
*/
|
|
114
|
+
halfOpenAfter: number;
|
|
115
|
+
/** The breaker policy controlling when the circuit trips. */
|
|
116
|
+
breaker: BreakerStrategy;
|
|
117
|
+
}
|
|
118
|
+
/** Timeout configuration of a named policy. Underlying work stops only when it cooperates with the abort signal. */
|
|
119
|
+
export interface TimeoutPolicyOptions {
|
|
120
|
+
/** Duration in milliseconds after which the call times out. */
|
|
121
|
+
duration: number;
|
|
122
|
+
/**
|
|
123
|
+
* - `aggressive` (default): reject immediately with `TaskCancelledError`.
|
|
124
|
+
* - `cooperative`: signal cancellation and wait for the call to settle.
|
|
125
|
+
*/
|
|
126
|
+
strategy?: 'aggressive' | 'cooperative';
|
|
127
|
+
}
|
|
128
|
+
/** Timeout configuration of the behavior. Underlying work stops only when it cooperates with the abort signal. */
|
|
129
|
+
export interface TimeoutOptions extends TimeoutPolicyOptions {
|
|
130
|
+
/**
|
|
131
|
+
* Explicit acknowledgement that an `aggressive` timeout is safe on a `command`
|
|
132
|
+
* or `event` handler. The caller is answered while the handler keeps running,
|
|
133
|
+
* so a retry, a released idempotency claim or a client retry can run the same
|
|
134
|
+
* side effect alongside it. Required for those request kinds unless the
|
|
135
|
+
* strategy is `cooperative`.
|
|
136
|
+
*/
|
|
137
|
+
replaySafe?: boolean;
|
|
138
|
+
}
|
|
139
|
+
/** Bulkhead configuration — limits concurrent in-flight executions. */
|
|
140
|
+
export interface BulkheadOptions {
|
|
141
|
+
/** Maximum number of concurrent executions. */
|
|
142
|
+
limit: number;
|
|
143
|
+
/** Optional number of queued executions allowed beyond `limit`. */
|
|
144
|
+
queue?: number;
|
|
145
|
+
}
|
|
146
|
+
/** Fallback configuration — substitutes a value when execution fails. */
|
|
147
|
+
export type FallbackOptions =
|
|
148
|
+
/** Return a static `value` when a handled failure occurs. */
|
|
149
|
+
{
|
|
150
|
+
value: unknown;
|
|
151
|
+
}
|
|
152
|
+
/** Lazily produce a value when a handled failure occurs. */
|
|
153
|
+
| {
|
|
154
|
+
factory: () => unknown;
|
|
155
|
+
};
|
|
156
|
+
/** What every telemetry hook receives. */
|
|
157
|
+
export interface ResilienceTelemetryEvent {
|
|
158
|
+
/** The named policy that fired the event; absent for a handler's policy. */
|
|
159
|
+
policyName?: string;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Optional telemetry hooks fired by the underlying cockatiel policies.
|
|
163
|
+
*
|
|
164
|
+
* These are attached once per policy: per handler for the behavior, per name
|
|
165
|
+
* for a named policy. They are scoped to that policy rather than to a single
|
|
166
|
+
* request.
|
|
167
|
+
*/
|
|
168
|
+
export interface ResilienceTelemetry {
|
|
169
|
+
/** Fired before each retry, with the upcoming attempt number and delay (ms). */
|
|
170
|
+
onRetry?(event: ResilienceTelemetryEvent & {
|
|
171
|
+
attempt: number;
|
|
172
|
+
delay: number;
|
|
173
|
+
/**
|
|
174
|
+
* The request that triggered this retry.
|
|
175
|
+
*
|
|
176
|
+
* A policy is cached per handler, so a handler registered for several event
|
|
177
|
+
* types shares one policy; without this the consumer could not tell which
|
|
178
|
+
* event is actually retrying.
|
|
179
|
+
*/
|
|
180
|
+
requestName?: string;
|
|
181
|
+
}): void;
|
|
182
|
+
/** Fired when the circuit breaker opens (trips). */
|
|
183
|
+
onCircuitOpen?(event: ResilienceTelemetryEvent): void;
|
|
184
|
+
/** Fired when the circuit breaker closes (recovers). */
|
|
185
|
+
onCircuitClose?(event: ResilienceTelemetryEvent): void;
|
|
186
|
+
/** Fired when the circuit breaker enters the half-open trial state. */
|
|
187
|
+
onCircuitHalfOpen?(event: ResilienceTelemetryEvent): void;
|
|
188
|
+
/** Fired when a timeout is reached. */
|
|
189
|
+
onTimeout?(event: ResilienceTelemetryEvent): void;
|
|
190
|
+
/** Fired when the bulkhead rejects a call (capacity + queue exhausted). */
|
|
191
|
+
onBulkheadRejected?(event: ResilienceTelemetryEvent): void;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* A named policy for an outbound dependency, declared once in
|
|
195
|
+
* `new ResiliencePolicies({ ... })` and shared by every caller through
|
|
196
|
+
* `ResiliencePolicies` or `@InjectResiliencePolicy(name)`.
|
|
197
|
+
*
|
|
198
|
+
* It wraps one outbound call, not a handler, so it offers every layer —
|
|
199
|
+
* a circuit breaker per dependency, a fallback value for one call — and needs
|
|
200
|
+
* no `replaySafe` acknowledgment: the adapter retries only its own call.
|
|
201
|
+
* Retry, circuit breaker and fallback still require `handle(error)` or
|
|
202
|
+
* `handleAllErrors: true`.
|
|
203
|
+
*
|
|
204
|
+
* @example A payment API shared by several handlers
|
|
205
|
+
* ```ts
|
|
206
|
+
* new ResiliencePolicies({
|
|
207
|
+
* paymentsApi: {
|
|
208
|
+
* handle: (error) => error instanceof PaymentGatewayUnavailableError,
|
|
209
|
+
* retry: { maxAttempts: 2, backoff: { type: 'exponential' } },
|
|
210
|
+
* circuitBreaker: { halfOpenAfter: 30_000, breaker: { type: 'consecutive', threshold: 5 } },
|
|
211
|
+
* timeout: { duration: 3_000, strategy: 'cooperative' },
|
|
212
|
+
* },
|
|
213
|
+
* });
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export interface ResiliencePolicyOptions {
|
|
217
|
+
/** Retry the call. */
|
|
218
|
+
retry?: RetryPolicyOptions;
|
|
219
|
+
/** Circuit breaker, shared by every caller of the policy. */
|
|
220
|
+
circuitBreaker?: CircuitBreakerOptions;
|
|
221
|
+
/** Concurrency limit, shared by every caller of the policy. */
|
|
222
|
+
bulkhead?: BulkheadOptions;
|
|
223
|
+
/** Timeout of one call. */
|
|
224
|
+
timeout?: TimeoutPolicyOptions;
|
|
225
|
+
/** Value returned in place of a handled failure. */
|
|
226
|
+
fallback?: FallbackOptions;
|
|
227
|
+
/** Selects the errors retry, circuit breaker and fallback act on. */
|
|
228
|
+
handle?: (error: unknown) => boolean;
|
|
229
|
+
/** Acts on every error; set it only deliberately. */
|
|
230
|
+
handleAllErrors?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Composition order, outermost first.
|
|
233
|
+
*
|
|
234
|
+
* @default ['fallback', 'retry', 'circuitBreaker', 'bulkhead', 'timeout']
|
|
235
|
+
*/
|
|
236
|
+
order?: ResilienceLayer[];
|
|
237
|
+
/** Telemetry hooks; every event carries the policy name. */
|
|
238
|
+
telemetry?: ResilienceTelemetry;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Per-handler (or global default) resilience configuration.
|
|
242
|
+
*
|
|
243
|
+
* Compose any subset of the layers below; only the ones you set are applied.
|
|
244
|
+
* Supply via `pipeline.wrap(options, [ResilienceBehavior, { ... }])` for a handler, or via
|
|
245
|
+
* the `ResilienceBehavior` constructor as application-wide defaults.
|
|
246
|
+
*
|
|
247
|
+
* ### Safety model
|
|
248
|
+
*
|
|
249
|
+
* Handler-level resilience wraps `next()`. A retry therefore replays everything
|
|
250
|
+
* downstream of this behavior, including the handler itself. Because that can
|
|
251
|
+
* repeat side effects, the package makes the dangerous choices explicit:
|
|
252
|
+
*
|
|
253
|
+
* - timeout / bulkhead may be configured without an error classifier;
|
|
254
|
+
* - retry requires `handle(error)` unless `handleAllErrors: true` is
|
|
255
|
+
* explicitly selected;
|
|
256
|
+
* - retries for commands/events additionally require `retry.replaySafe: true`.
|
|
257
|
+
*
|
|
258
|
+
* A circuit breaker and a fallback belong to an outbound dependency, not to a
|
|
259
|
+
* handler: declare them on a named policy (`new ResiliencePolicies({ ... })`)
|
|
260
|
+
* and use it in the adapter, so only the remote call is repeated or short-circuited.
|
|
261
|
+
* The behavior contract rejects them here.
|
|
262
|
+
*
|
|
263
|
+
* @example Query retry with an explicit transient-error classifier
|
|
264
|
+
* ```ts
|
|
265
|
+
* class GetCatalogHandler {
|
|
266
|
+
* @pipeline.wrap({ kind: 'query' }, [ResilienceBehavior, {
|
|
267
|
+
* retry: { maxAttempts: 3, backoff: { type: 'exponential' } },
|
|
268
|
+
* timeout: { duration: 2_000 },
|
|
269
|
+
* handle: (error) => error instanceof CatalogUnavailableError,
|
|
270
|
+
* }])
|
|
271
|
+
* async handle(query: GetCatalogQuery) {}
|
|
272
|
+
* }
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* @example Command timeout without retry
|
|
276
|
+
* ```ts
|
|
277
|
+
* class RebuildProjectionHandler {
|
|
278
|
+
* @pipeline.wrap({ kind: 'command' }, [ResilienceBehavior, {
|
|
279
|
+
* timeout: { duration: 30_000, strategy: 'cooperative' },
|
|
280
|
+
* }])
|
|
281
|
+
* async handle(command: RebuildProjectionCommand) {}
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
export interface ResilienceBehaviorOptions {
|
|
286
|
+
/** Retry policy. */
|
|
287
|
+
retry?: RetryOptions;
|
|
288
|
+
/** Bulkhead (concurrency limiter) policy. Reused across invocations. */
|
|
289
|
+
bulkhead?: BulkheadOptions;
|
|
290
|
+
/** Timeout policy. */
|
|
291
|
+
timeout?: TimeoutOptions;
|
|
292
|
+
/**
|
|
293
|
+
* Predicate selecting which thrown errors are treated as *handled* failures
|
|
294
|
+
* (eligible for retry). Return `true` only for failures that really are safe
|
|
295
|
+
* for the configured policy.
|
|
296
|
+
*
|
|
297
|
+
* A declarative retry requires an explicit classifier.
|
|
298
|
+
* Use {@link handleAllErrors} only when handling every thrown error is
|
|
299
|
+
* intentionally part of the policy.
|
|
300
|
+
*/
|
|
301
|
+
handle?: (error: unknown) => boolean;
|
|
302
|
+
/**
|
|
303
|
+
* Explicitly opt into Cockatiel's `handleAll` semantics when no classifier is
|
|
304
|
+
* supplied. Prefer {@link handle} in production so validation, authorization,
|
|
305
|
+
* domain and programmer errors are not retried.
|
|
306
|
+
*/
|
|
307
|
+
handleAllErrors?: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* Override the composition order of the configured layers. Only the listed,
|
|
310
|
+
* configured layers are wrapped; unlisted layers are skipped. The first entry
|
|
311
|
+
* is the outermost wrapper, the last is closest to the handler.
|
|
312
|
+
*
|
|
313
|
+
* @default ['retry', 'bulkhead', 'timeout']
|
|
314
|
+
*/
|
|
315
|
+
order?: HandlerResilienceLayer[];
|
|
316
|
+
/** Optional telemetry hooks. */
|
|
317
|
+
telemetry?: ResilienceTelemetry;
|
|
318
|
+
/**
|
|
319
|
+
* Escape hatch: provide a fully pre-built cockatiel `IPolicy`. When set, all
|
|
320
|
+
* declarative options above are ignored and this policy is used verbatim.
|
|
321
|
+
* Declarative safety validation is skipped because the caller owns the policy
|
|
322
|
+
* semantics directly.
|
|
323
|
+
*/
|
|
324
|
+
policy?: IPolicy;
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=resilience-options.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-options.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/resilience-options.interface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-options.interface.js","sourceRoot":"","sources":["../../src/interfaces/resilience-options.interface.ts"],"names":[],"mappings":"AAAA,sEAAsE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { PipelineLogger } from '@cqrs-ddd/pipeline';
|
|
2
|
+
import type { IDefaultPolicyContext } from 'cockatiel';
|
|
3
|
+
import { type AnyPolicy } from './helpers/policy-factory.js';
|
|
4
|
+
import type { ResiliencePolicyOptions } from './interfaces/resilience-options.interface.js';
|
|
5
|
+
/**
|
|
6
|
+
* The named policies of the application, for outbound adapters: a payment API
|
|
7
|
+
* client, an SMTP sender, a partner webhook.
|
|
8
|
+
*
|
|
9
|
+
* Every policy declared in the constructor's `options` is built once, when this registry is created at startup, and
|
|
10
|
+
* shared by every caller — so a circuit breaker or bulkhead tracks the
|
|
11
|
+
* dependency, whatever handler calls it. An invalid policy fails startup with
|
|
12
|
+
* {@link ResiliencePolicyConfigurationError}.
|
|
13
|
+
*
|
|
14
|
+
* @example An adapter running its call through a shared policy
|
|
15
|
+
* ```ts
|
|
16
|
+
* export class PaymentsClient {
|
|
17
|
+
* constructor(private readonly policies: ResiliencePolicies) {}
|
|
18
|
+
*
|
|
19
|
+
* charge(order: Order): Promise<Receipt> {
|
|
20
|
+
* return this.policies.execute('paymentsApi', ({ signal }) =>
|
|
21
|
+
* this.http.post('/charges', order, { signal }),
|
|
22
|
+
* );
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class ResiliencePolicies {
|
|
28
|
+
private readonly policies;
|
|
29
|
+
constructor(options?: Record<string, ResiliencePolicyOptions>, logger?: PipelineLogger);
|
|
30
|
+
/** The declared policy names, in declaration order. */
|
|
31
|
+
get names(): readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* Returns the shared cockatiel policy declared under `name`.
|
|
34
|
+
*
|
|
35
|
+
* @throws ResiliencePolicyConfigurationError when no policy has that name.
|
|
36
|
+
*/
|
|
37
|
+
get(name: string): AnyPolicy;
|
|
38
|
+
/**
|
|
39
|
+
* Runs `fn` through the policy declared under `name`. `fn` receives the
|
|
40
|
+
* policy's `signal`, aborted on a cooperative timeout: pass it to the
|
|
41
|
+
* outbound call so the call really stops. With a fallback, the fallback
|
|
42
|
+
* value is returned in place of a handled failure.
|
|
43
|
+
*
|
|
44
|
+
* @throws ResiliencePolicyConfigurationError when no policy has that name.
|
|
45
|
+
*/
|
|
46
|
+
execute<T>(name: string, fn: (context: IDefaultPolicyContext) => PromiseLike<T> | T): Promise<T>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=resilience-policies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-policies.d.ts","sourceRoot":"","sources":["../src/resilience-policies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EACL,KAAK,SAAS,EAEf,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAE5F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAEzD,YACE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EACjD,MAAM,CAAC,EAAE,cAAc,EAMxB;IAED,uDAAuD;IACvD,IAAI,KAAK,IAAI,SAAS,MAAM,EAAE,CAE7B;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAU3B;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,EACP,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,GACzD,OAAO,CAAC,CAAC,CAAC,CAEZ;CACF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { ResiliencePolicyConfigurationError } from './errors/resilience-policy-configuration.error.js';
|
|
3
|
+
import { buildResiliencePolicy, } from './helpers/policy-factory.js';
|
|
4
|
+
/**
|
|
5
|
+
* The named policies of the application, for outbound adapters: a payment API
|
|
6
|
+
* client, an SMTP sender, a partner webhook.
|
|
7
|
+
*
|
|
8
|
+
* Every policy declared in the constructor's `options` is built once, when this registry is created at startup, and
|
|
9
|
+
* shared by every caller — so a circuit breaker or bulkhead tracks the
|
|
10
|
+
* dependency, whatever handler calls it. An invalid policy fails startup with
|
|
11
|
+
* {@link ResiliencePolicyConfigurationError}.
|
|
12
|
+
*
|
|
13
|
+
* @example An adapter running its call through a shared policy
|
|
14
|
+
* ```ts
|
|
15
|
+
* export class PaymentsClient {
|
|
16
|
+
* constructor(private readonly policies: ResiliencePolicies) {}
|
|
17
|
+
*
|
|
18
|
+
* charge(order: Order): Promise<Receipt> {
|
|
19
|
+
* return this.policies.execute('paymentsApi', ({ signal }) =>
|
|
20
|
+
* this.http.post('/charges', order, { signal }),
|
|
21
|
+
* );
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class ResiliencePolicies {
|
|
27
|
+
policies = new Map();
|
|
28
|
+
constructor(options, logger) {
|
|
29
|
+
const log = logger ?? console;
|
|
30
|
+
for (const [name, policyOptions] of Object.entries(options ?? {})) {
|
|
31
|
+
this.policies.set(name, buildNamedPolicy(name, policyOptions, log));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** The declared policy names, in declaration order. */
|
|
35
|
+
get names() {
|
|
36
|
+
return [...this.policies.keys()];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Returns the shared cockatiel policy declared under `name`.
|
|
40
|
+
*
|
|
41
|
+
* @throws ResiliencePolicyConfigurationError when no policy has that name.
|
|
42
|
+
*/
|
|
43
|
+
get(name) {
|
|
44
|
+
const policy = this.policies.get(name);
|
|
45
|
+
if (!policy) {
|
|
46
|
+
const declared = this.names.length > 0 ? this.names.join(', ') : '(none)';
|
|
47
|
+
throw new ResiliencePolicyConfigurationError(name, `no policy has this name; declared: ${declared}`);
|
|
48
|
+
}
|
|
49
|
+
return policy;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Runs `fn` through the policy declared under `name`. `fn` receives the
|
|
53
|
+
* policy's `signal`, aborted on a cooperative timeout: pass it to the
|
|
54
|
+
* outbound call so the call really stops. With a fallback, the fallback
|
|
55
|
+
* value is returned in place of a handled failure.
|
|
56
|
+
*
|
|
57
|
+
* @throws ResiliencePolicyConfigurationError when no policy has that name.
|
|
58
|
+
*/
|
|
59
|
+
execute(name, fn) {
|
|
60
|
+
return this.get(name).execute(fn);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function buildNamedPolicy(name, options, logger) {
|
|
64
|
+
const classifiesErrors = typeof options.handle === 'function' || options.handleAllErrors === true;
|
|
65
|
+
if ((options.retry || options.circuitBreaker || options.fallback) &&
|
|
66
|
+
!classifiesErrors) {
|
|
67
|
+
throw new ResiliencePolicyConfigurationError(name, 'retry, circuitBreaker and fallback require handle(error) or handleAllErrors: true');
|
|
68
|
+
}
|
|
69
|
+
const policy = buildResiliencePolicy(options, { logger, policyName: name });
|
|
70
|
+
if (!policy) {
|
|
71
|
+
throw new ResiliencePolicyConfigurationError(name, 'it configures no layer (retry, circuitBreaker, bulkhead, timeout or fallback)');
|
|
72
|
+
}
|
|
73
|
+
return policy;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=resilience-policies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-policies.js","sourceRoot":"","sources":["../src/resilience-policies.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAItE,OAAO,EAAE,kCAAkC,EAAE,MAAM,mDAAmD,CAAC;AACvG,OAAO,EAEL,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AAGrC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,kBAAkB;IACZ,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAEzD,YACE,OAAiD,EACjD,MAAuB;QAEvB,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAClE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,IAAI,KAAK;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAY;QACd,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC1E,MAAM,IAAI,kCAAkC,CAC1C,IAAI,EACJ,sCAAsC,QAAQ,EAAE,CACjD,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CACL,IAAY,EACZ,EAA0D;QAE1D,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAe,CAAC;IAClD,CAAC;CACF;AAED,SAAS,gBAAgB,CACvB,IAAY,EACZ,OAAgC,EAChC,MAAsB;IAEtB,MAAM,gBAAgB,GACpB,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,OAAO,CAAC,eAAe,KAAK,IAAI,CAAC;IAC3E,IACE,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,QAAQ,CAAC;QAC7D,CAAC,gBAAgB,EACjB,CAAC;QACD,MAAM,IAAI,kCAAkC,CAC1C,IAAI,EACJ,mFAAmF,CACpF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,kCAAkC,CAC1C,IAAI,EACJ,+EAA+E,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { PipelineLogger } from '@cqrs-ddd/pipeline';
|
|
2
|
+
import { type IPipelineBehavior, type IPipelineBehaviorContract, type IPipelineBehaviorOptionsResolver, type IPipelineContext, type NextDelegate, PIPELINE_BEHAVIOR_CONTRACT } from '@cqrs-ddd/pipeline';
|
|
3
|
+
import type { ResilienceBehaviorOptions } from './interfaces/resilience-options.interface.js';
|
|
4
|
+
/**
|
|
5
|
+
* Pipeline behavior that wraps each command / query / event handler in a
|
|
6
|
+
* cockatiel resilience policy — the layers that make sense around a whole
|
|
7
|
+
* handler: retry, timeout and bulkhead.
|
|
8
|
+
*
|
|
9
|
+
* A circuit breaker and a fallback belong to an outbound dependency, not to a
|
|
10
|
+
* handler: declare them on a named policy (`new ResiliencePolicies({ ... })`)
|
|
11
|
+
* and use it in the adapter through {@link ResiliencePolicies}. The behavior
|
|
12
|
+
* contract rejects them here.
|
|
13
|
+
*
|
|
14
|
+
* Resolution of the effective options for a handler where this behavior is
|
|
15
|
+
* attached:
|
|
16
|
+
* 1. Application-wide defaults, the first constructor argument.
|
|
17
|
+
* 2. Per-handler options from `pipeline.wrap(options, [ResilienceBehavior, { ... }])`,
|
|
18
|
+
* shallow-merged on top of the defaults (handler keys win).
|
|
19
|
+
*
|
|
20
|
+
* Policies are built **lazily on first invocation and cached per handler**, so
|
|
21
|
+
* a stateful layer (bulkhead) correctly shares state across
|
|
22
|
+
* every request to that handler. When no options resolve, the behavior caches
|
|
23
|
+
* that result and passes subsequent invocations directly to `next()` without
|
|
24
|
+
* constructing or executing a cockatiel policy.
|
|
25
|
+
*
|
|
26
|
+
* ### Replay / error-classification safety
|
|
27
|
+
*
|
|
28
|
+
* A handler-level retry calls `next()` again, which means the complete
|
|
29
|
+
* downstream pipeline and handler are replayed. To avoid accidental duplicate
|
|
30
|
+
* side effects, command/event retries must explicitly set
|
|
31
|
+
* `retry.replaySafe: true`. A retry must also define which errors are transient via `handle(error)`, unless the caller
|
|
32
|
+
* intentionally opts into `handleAllErrors: true`. An `aggressive` timeout
|
|
33
|
+
* (the default strategy) on a command/event answers the caller while the
|
|
34
|
+
* handler keeps running, so it requires `strategy: 'cooperative'` or
|
|
35
|
+
* `timeout.replaySafe: true`.
|
|
36
|
+
*
|
|
37
|
+
* Timeout and bulkhead-only policies do not require an error classifier because
|
|
38
|
+
* they do not decide which application errors are retryable.
|
|
39
|
+
* A custom pre-built Cockatiel `policy` also bypasses the declarative safety
|
|
40
|
+
* checks because the caller owns its semantics directly.
|
|
41
|
+
*/
|
|
42
|
+
export declare class ResilienceBehavior implements IPipelineBehavior, IPipelineBehaviorOptionsResolver<ResilienceBehaviorOptions> {
|
|
43
|
+
private readonly defaultOptions?;
|
|
44
|
+
static readonly [PIPELINE_BEHAVIOR_CONTRACT]: IPipelineBehaviorContract;
|
|
45
|
+
private readonly logger;
|
|
46
|
+
/**
|
|
47
|
+
* Per-handler policy cache. `null` means "resolved, but nothing configured"
|
|
48
|
+
* (pass-through), distinct from `undefined` ("not yet resolved").
|
|
49
|
+
*/
|
|
50
|
+
private readonly policyCache;
|
|
51
|
+
constructor(defaultOptions?: ResilienceBehaviorOptions | undefined, logger?: PipelineLogger);
|
|
52
|
+
handle(context: IPipelineContext, next: NextDelegate): Promise<unknown>;
|
|
53
|
+
/** Resolves, validates, and caches the composed policy for the handler in `context`. */
|
|
54
|
+
private resolvePolicy;
|
|
55
|
+
/**
|
|
56
|
+
* Rejects ambiguous whole-handler resilience configurations before Cockatiel
|
|
57
|
+
* policy creation. This turns replay/error-classification assumptions into an
|
|
58
|
+
* explicit application decision instead of a hidden default.
|
|
59
|
+
*/
|
|
60
|
+
private assertSafeConfiguration;
|
|
61
|
+
/** Shallow-merges pipeline-level options over the constructor defaults. */
|
|
62
|
+
resolveEffectiveOptions(options?: ResilienceBehaviorOptions): ResilienceBehaviorOptions | undefined;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=resilience.behavior.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.behavior.d.ts","sourceRoot":"","sources":["../src/resilience.behavior.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,gCAAgC,EACrC,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,0BAA0B,EAG3B,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AAgE9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,kBACX,YACE,iBAAiB,EACjB,gCAAgC,CAAC,yBAAyB,CAAC;IA6B3D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IA3BlC,MAAM,CAAC,QAAQ,CAAC,CAAC,0BAA0B,CAAC,EAAE,yBAAyB,CAiBrE;IAEF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4C;IAExE,YACmB,cAAc,CAAC,EAAE,yBAAyB,YAAA,EAC3D,MAAM,CAAC,EAAE,cAAc,EAGxB;IAEK,MAAM,CACV,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,OAAO,CAAC,CAkBlB;IAED,wFAAwF;IACxF,OAAO,CAAC,aAAa;IAsBrB;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAc/B,2EAA2E;IAC3E,uBAAuB,CACrB,OAAO,CAAC,EAAE,yBAAyB,GAClC,yBAAyB,GAAG,SAAS,CAGvC;CACF"}
|