@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
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @cqrs-ddd/pipeline-resilience
|
|
2
|
+
|
|
3
|
+
Retry, timeout and bulkhead policies around an operation, and named policies (retry,
|
|
4
|
+
circuit breaker, timeout, fallback) for outbound dependencies, for `@cqrs-ddd/pipeline`,
|
|
5
|
+
built on [cockatiel](https://github.com/connor4312/cockatiel). A retried command must be
|
|
6
|
+
declared replay-safe; a misconfiguration fails when the function is wrapped.
|
|
7
|
+
|
|
8
|
+
**Documentation:** [guide](https://aristoteliss.github.io/ddd-cqrs/packages/pipeline-resilience/) · [API reference](https://aristoteliss.github.io/ddd-cqrs/api/cqrs-ddd/pipeline-resilience/) · [all packages](https://aristoteliss.github.io/ddd-cqrs/)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm add @cqrs-ddd/pipeline-resilience @cqrs-ddd/pipeline cockatiel
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Requires Node.js 22.12 or later. Published as an ES module; a CommonJS application loads
|
|
17
|
+
it with `require()`.
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
export const lookup = pipeline.wrap(
|
|
23
|
+
{ name: 'lookup', kind: 'query' },
|
|
24
|
+
resilience({ retry: { maxAttempts: 2 }, handle: (e) => e instanceof TransientError }),
|
|
25
|
+
)(async (id: string) => catalog.find(id));
|
|
26
|
+
|
|
27
|
+
const policies = new ResiliencePolicies({
|
|
28
|
+
paymentsApi: { handleAllErrors: true, timeout: { duration: 3_000 } },
|
|
29
|
+
});
|
|
30
|
+
await policies.execute('paymentsApi', () => payments.charge(order));
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
Dual-licensed under **AGPLv3** and a **Commercial License**. See `LICENSE` and
|
|
36
|
+
`COMMERCIAL_LICENSE.txt`.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raised before execution when a declarative handler-level resilience policy is
|
|
3
|
+
* ambiguous or unsafe (for example a side-effectful command retry without an
|
|
4
|
+
* explicit replay-safety acknowledgement).
|
|
5
|
+
*/
|
|
6
|
+
export declare class ResilienceConfigurationError extends Error {
|
|
7
|
+
readonly requestName: string;
|
|
8
|
+
readonly requestKind: string;
|
|
9
|
+
readonly reason: string;
|
|
10
|
+
readonly name = "ResilienceConfigurationError";
|
|
11
|
+
constructor(requestName: string, requestKind: string, reason: string);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=resilience-configuration.error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-configuration.error.d.ts","sourceRoot":"","sources":["../../src/errors/resilience-configuration.error.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;aAInC,WAAW,EAAE,MAAM;aACnB,WAAW,EAAE,MAAM;aACnB,MAAM,EAAE,MAAM;IALhC,SAAkB,IAAI,kCAAkC;IAExD,YACkB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAK/B;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
/**
|
|
3
|
+
* Raised before execution when a declarative handler-level resilience policy is
|
|
4
|
+
* ambiguous or unsafe (for example a side-effectful command retry without an
|
|
5
|
+
* explicit replay-safety acknowledgement).
|
|
6
|
+
*/
|
|
7
|
+
export class ResilienceConfigurationError extends Error {
|
|
8
|
+
requestName;
|
|
9
|
+
requestKind;
|
|
10
|
+
reason;
|
|
11
|
+
name = 'ResilienceConfigurationError';
|
|
12
|
+
constructor(requestName, requestKind, reason) {
|
|
13
|
+
super(`Unsafe resilience configuration for ${requestKind} ${requestName}: ${reason}`);
|
|
14
|
+
this.requestName = requestName;
|
|
15
|
+
this.requestKind = requestKind;
|
|
16
|
+
this.reason = reason;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=resilience-configuration.error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-configuration.error.js","sourceRoot":"","sources":["../../src/errors/resilience-configuration.error.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE;;;;GAIG;AACH,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAInC,WAAW;IACX,WAAW;IACX,MAAM;IALN,IAAI,GAAG,8BAA8B,CAAC;IAExD,YACkB,WAAmB,EACnB,WAAmB,EACnB,MAAc;QAE9B,KAAK,CACH,uCAAuC,WAAW,IAAI,WAAW,KAAK,MAAM,EAAE,CAC/E,CAAC;2BANc,WAAW;2BACX,WAAW;sBACX,MAAM;IAKxB,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raised at startup when a named policy is invalid (for example a retry
|
|
3
|
+
* without an error classifier, or no layer at all), and when code asks
|
|
4
|
+
* {@link ResiliencePolicies} for a name that was never declared.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ResiliencePolicyConfigurationError extends Error {
|
|
7
|
+
readonly policyName: string;
|
|
8
|
+
readonly reason: string;
|
|
9
|
+
readonly name = "ResiliencePolicyConfigurationError";
|
|
10
|
+
constructor(policyName: string, reason: string);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=resilience-policy-configuration.error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-policy-configuration.error.d.ts","sourceRoot":"","sources":["../../src/errors/resilience-policy-configuration.error.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,kCAAmC,SAAQ,KAAK;aAIzC,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;IAJhC,SAAkB,IAAI,wCAAwC;IAE9D,YACkB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EAG/B;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
/**
|
|
3
|
+
* Raised at startup when a named policy is invalid (for example a retry
|
|
4
|
+
* without an error classifier, or no layer at all), and when code asks
|
|
5
|
+
* {@link ResiliencePolicies} for a name that was never declared.
|
|
6
|
+
*/
|
|
7
|
+
export class ResiliencePolicyConfigurationError extends Error {
|
|
8
|
+
policyName;
|
|
9
|
+
reason;
|
|
10
|
+
name = 'ResiliencePolicyConfigurationError';
|
|
11
|
+
constructor(policyName, reason) {
|
|
12
|
+
super(`Invalid resilience policy '${policyName}': ${reason}`);
|
|
13
|
+
this.policyName = policyName;
|
|
14
|
+
this.reason = reason;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=resilience-policy-configuration.error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-policy-configuration.error.js","sourceRoot":"","sources":["../../src/errors/resilience-policy-configuration.error.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE;;;;GAIG;AACH,MAAM,OAAO,kCAAmC,SAAQ,KAAK;IAIzC,UAAU;IACV,MAAM;IAJN,IAAI,GAAG,oCAAoC,CAAC;IAE9D,YACkB,UAAkB,EAClB,MAAc;QAE9B,KAAK,CAAC,8BAA8B,UAAU,MAAM,MAAM,EAAE,CAAC,CAAC;0BAH9C,UAAU;sBACV,MAAM;IAGxB,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PipelineLogger } from '@cqrs-ddd/pipeline';
|
|
2
|
+
import { type IDefaultPolicyContext, type IPolicy } from 'cockatiel';
|
|
3
|
+
import type { ResiliencePolicyOptions, ResilienceTelemetry } from '../interfaces/resilience-options.interface.js';
|
|
4
|
+
/** Any composed cockatiel policy (allowing a fallback's alternate return). */
|
|
5
|
+
export type AnyPolicy = IPolicy<IDefaultPolicyContext, unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Contextual metadata used to enrich telemetry/log messages.
|
|
8
|
+
*
|
|
9
|
+
* A handler's policy passes `requestName` and `handlerName`, which are
|
|
10
|
+
* build-time fallbacks only: the policy is built once per handler and reused,
|
|
11
|
+
* so the live values are read from the request-scoped store at emit time. A
|
|
12
|
+
* named policy passes `policyName` instead.
|
|
13
|
+
*/
|
|
14
|
+
export interface PolicyBuildContext {
|
|
15
|
+
logger?: PipelineLogger;
|
|
16
|
+
requestName?: string;
|
|
17
|
+
handlerName?: string;
|
|
18
|
+
/** Name of a named policy; log messages and telemetry events carry it. */
|
|
19
|
+
policyName?: string;
|
|
20
|
+
telemetry?: ResilienceTelemetry;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Builds a single composed cockatiel {@link IPolicy} from declarative options
|
|
24
|
+
* — a named policy's {@link ResiliencePolicyOptions} or a handler's
|
|
25
|
+
* `ResilienceBehaviorOptions` — or `null` when nothing is configured.
|
|
26
|
+
*
|
|
27
|
+
* The policy is intended to be built **once** (per handler, or per name) and
|
|
28
|
+
* reused so that stateful layers (circuit breaker, bulkhead) retain their
|
|
29
|
+
* state across invocations.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildResiliencePolicy(options: ResiliencePolicyOptions & {
|
|
32
|
+
policy?: IPolicy;
|
|
33
|
+
}, ctx: PolicyBuildContext): AnyPolicy | null;
|
|
34
|
+
//# sourceMappingURL=policy-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-factory.d.ts","sourceRoot":"","sources":["../../src/helpers/policy-factory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAcL,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EASb,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAMV,uBAAuB,EACvB,mBAAmB,EAKpB,MAAM,+CAA+C,CAAC;AAiBvD,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAuLD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,uBAAuB,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EACvD,GAAG,EAAE,kBAAkB,GACtB,SAAS,GAAG,IAAI,CAiClB"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { bulkhead, ConsecutiveBreaker, ConstantBackoff, CountBreaker, circuitBreaker, decorrelatedJitterGenerator, ExponentialBackoff, fallback, fullJitterGenerator, halfJitterGenerator, handleAll, handleWhen, IterableBackoff, noJitterGenerator, retry, SamplingBreaker, TimeoutStrategy, timeout, wrap, } from 'cockatiel';
|
|
3
|
+
import { getResilienceRequestLabels, } from './resilience-context.js';
|
|
4
|
+
/** Default outermost → innermost composition order of the resilience layers. */
|
|
5
|
+
const DEFAULT_ORDER = [
|
|
6
|
+
'fallback',
|
|
7
|
+
'retry',
|
|
8
|
+
'circuitBreaker',
|
|
9
|
+
'bulkhead',
|
|
10
|
+
'timeout',
|
|
11
|
+
];
|
|
12
|
+
const LOG_CONTEXT = 'ResilienceBehavior';
|
|
13
|
+
/** Resolves the live request labels, falling back to the build-time values. */
|
|
14
|
+
function labels(ctx) {
|
|
15
|
+
return (getResilienceRequestLabels() ?? {
|
|
16
|
+
requestName: ctx.requestName,
|
|
17
|
+
handlerName: ctx.handlerName,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** What a log message names: the named policy, or the live handler. */
|
|
21
|
+
function subject(ctx) {
|
|
22
|
+
return ctx.policyName !== undefined
|
|
23
|
+
? `policy '${ctx.policyName}'`
|
|
24
|
+
: labels(ctx).handlerName;
|
|
25
|
+
}
|
|
26
|
+
/** The event every telemetry hook receives. */
|
|
27
|
+
function telemetryEvent(ctx) {
|
|
28
|
+
return { policyName: ctx.policyName };
|
|
29
|
+
}
|
|
30
|
+
/** Maps a {@link JitterStrategy} to its cockatiel generator function. */
|
|
31
|
+
function jitterGenerator(strategy) {
|
|
32
|
+
switch (strategy) {
|
|
33
|
+
case 'none':
|
|
34
|
+
return noJitterGenerator;
|
|
35
|
+
case 'full':
|
|
36
|
+
return fullJitterGenerator;
|
|
37
|
+
case 'half':
|
|
38
|
+
return halfJitterGenerator;
|
|
39
|
+
default:
|
|
40
|
+
return decorrelatedJitterGenerator;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Builds a cockatiel backoff factory from declarative {@link RetryBackoff}. */
|
|
44
|
+
function buildBackoff(backoff) {
|
|
45
|
+
switch (backoff.type) {
|
|
46
|
+
case 'constant':
|
|
47
|
+
return new ConstantBackoff(backoff.delay);
|
|
48
|
+
case 'iterable':
|
|
49
|
+
return new IterableBackoff(backoff.delays);
|
|
50
|
+
case 'exponential': {
|
|
51
|
+
const options = {
|
|
52
|
+
generator: jitterGenerator(backoff.jitter),
|
|
53
|
+
};
|
|
54
|
+
if (backoff.initialDelay !== undefined)
|
|
55
|
+
options.initialDelay = backoff.initialDelay;
|
|
56
|
+
if (backoff.maxDelay !== undefined)
|
|
57
|
+
options.maxDelay = backoff.maxDelay;
|
|
58
|
+
if (backoff.exponent !== undefined)
|
|
59
|
+
options.exponent = backoff.exponent;
|
|
60
|
+
return new ExponentialBackoff(options);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Builds the cockatiel breaker from a declarative {@link CircuitBreakerOptions}. */
|
|
65
|
+
function buildBreaker(options) {
|
|
66
|
+
const breaker = options.breaker;
|
|
67
|
+
switch (breaker.type) {
|
|
68
|
+
case 'consecutive':
|
|
69
|
+
return new ConsecutiveBreaker(breaker.threshold);
|
|
70
|
+
case 'sampling':
|
|
71
|
+
return new SamplingBreaker({
|
|
72
|
+
threshold: breaker.threshold,
|
|
73
|
+
duration: breaker.duration,
|
|
74
|
+
minimumRps: breaker.minimumRps,
|
|
75
|
+
});
|
|
76
|
+
case 'count':
|
|
77
|
+
return new CountBreaker({
|
|
78
|
+
threshold: breaker.threshold,
|
|
79
|
+
size: breaker.size,
|
|
80
|
+
minimumNumberOfCalls: breaker.minimumNumberOfCalls,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function buildRetry(options, base, ctx) {
|
|
85
|
+
const policy = retry(base, {
|
|
86
|
+
maxAttempts: options.maxAttempts,
|
|
87
|
+
backoff: options.backoff ? buildBackoff(options.backoff) : undefined,
|
|
88
|
+
});
|
|
89
|
+
policy.onRetry((event) => {
|
|
90
|
+
const { requestName, handlerName } = labels(ctx);
|
|
91
|
+
const retrying = ctx.policyName !== undefined
|
|
92
|
+
? `policy '${ctx.policyName}'`
|
|
93
|
+
: `${requestName} → ${handlerName}`;
|
|
94
|
+
ctx.logger?.debug?.(`[resilience] retrying ${retrying} ` +
|
|
95
|
+
`(attempt ${event.attempt}, delay ${event.delay}ms)`, LOG_CONTEXT);
|
|
96
|
+
ctx.telemetry?.onRetry?.({
|
|
97
|
+
...telemetryEvent(ctx),
|
|
98
|
+
attempt: event.attempt,
|
|
99
|
+
delay: event.delay,
|
|
100
|
+
requestName,
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
return policy;
|
|
104
|
+
}
|
|
105
|
+
function buildCircuitBreaker(options, base, ctx) {
|
|
106
|
+
const policy = circuitBreaker(base, {
|
|
107
|
+
halfOpenAfter: options.halfOpenAfter,
|
|
108
|
+
breaker: buildBreaker(options),
|
|
109
|
+
});
|
|
110
|
+
policy.onBreak(() => {
|
|
111
|
+
ctx.logger?.warn?.(`[resilience] circuit OPEN for ${subject(ctx)}`, LOG_CONTEXT);
|
|
112
|
+
ctx.telemetry?.onCircuitOpen?.(telemetryEvent(ctx));
|
|
113
|
+
});
|
|
114
|
+
policy.onReset(() => {
|
|
115
|
+
ctx.logger?.log?.(`[resilience] circuit CLOSED for ${subject(ctx)}`, LOG_CONTEXT);
|
|
116
|
+
ctx.telemetry?.onCircuitClose?.(telemetryEvent(ctx));
|
|
117
|
+
});
|
|
118
|
+
policy.onHalfOpen(() => {
|
|
119
|
+
ctx.logger?.debug?.(`[resilience] circuit HALF-OPEN for ${subject(ctx)}`, LOG_CONTEXT);
|
|
120
|
+
ctx.telemetry?.onCircuitHalfOpen?.(telemetryEvent(ctx));
|
|
121
|
+
});
|
|
122
|
+
return policy;
|
|
123
|
+
}
|
|
124
|
+
function buildBulkhead(options, ctx) {
|
|
125
|
+
const policy = bulkhead(options.limit, options.queue ?? 0);
|
|
126
|
+
policy.onReject(() => {
|
|
127
|
+
ctx.logger?.warn?.(`[resilience] bulkhead rejected ${subject(ctx)} ` +
|
|
128
|
+
`(limit ${options.limit}, queue ${options.queue ?? 0})`, LOG_CONTEXT);
|
|
129
|
+
ctx.telemetry?.onBulkheadRejected?.(telemetryEvent(ctx));
|
|
130
|
+
});
|
|
131
|
+
return policy;
|
|
132
|
+
}
|
|
133
|
+
function buildTimeout(options, ctx) {
|
|
134
|
+
const strategy = options.strategy === 'cooperative'
|
|
135
|
+
? TimeoutStrategy.Cooperative
|
|
136
|
+
: TimeoutStrategy.Aggressive;
|
|
137
|
+
const policy = timeout(options.duration, strategy);
|
|
138
|
+
policy.onTimeout(() => {
|
|
139
|
+
ctx.logger?.warn?.(`[resilience] timeout after ${options.duration}ms for ${subject(ctx)}`, LOG_CONTEXT);
|
|
140
|
+
ctx.telemetry?.onTimeout?.(telemetryEvent(ctx));
|
|
141
|
+
});
|
|
142
|
+
return policy;
|
|
143
|
+
}
|
|
144
|
+
function buildFallback(options, base) {
|
|
145
|
+
const valueOrFactory = 'factory' in options ? () => options.factory() : options.value;
|
|
146
|
+
return fallback(base, valueOrFactory);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Builds a single composed cockatiel {@link IPolicy} from declarative options
|
|
150
|
+
* — a named policy's {@link ResiliencePolicyOptions} or a handler's
|
|
151
|
+
* `ResilienceBehaviorOptions` — or `null` when nothing is configured.
|
|
152
|
+
*
|
|
153
|
+
* The policy is intended to be built **once** (per handler, or per name) and
|
|
154
|
+
* reused so that stateful layers (circuit breaker, bulkhead) retain their
|
|
155
|
+
* state across invocations.
|
|
156
|
+
*/
|
|
157
|
+
export function buildResiliencePolicy(options, ctx) {
|
|
158
|
+
// Escape hatch: a fully pre-built policy wins over everything else.
|
|
159
|
+
if (options.policy)
|
|
160
|
+
return options.policy;
|
|
161
|
+
const base = options.handle
|
|
162
|
+
? handleWhen((error) => options.handle?.(error) ?? false)
|
|
163
|
+
: handleAll;
|
|
164
|
+
const buildCtx = { ...ctx, telemetry: options.telemetry };
|
|
165
|
+
const layers = {};
|
|
166
|
+
if (options.retry)
|
|
167
|
+
layers.retry = buildRetry(options.retry, base, buildCtx);
|
|
168
|
+
if (options.circuitBreaker)
|
|
169
|
+
layers.circuitBreaker = buildCircuitBreaker(options.circuitBreaker, base, buildCtx);
|
|
170
|
+
if (options.bulkhead)
|
|
171
|
+
layers.bulkhead = buildBulkhead(options.bulkhead, buildCtx);
|
|
172
|
+
if (options.timeout)
|
|
173
|
+
layers.timeout = buildTimeout(options.timeout, buildCtx);
|
|
174
|
+
if (options.fallback)
|
|
175
|
+
layers.fallback = buildFallback(options.fallback, base);
|
|
176
|
+
const order = options.order ?? DEFAULT_ORDER;
|
|
177
|
+
const composed = [];
|
|
178
|
+
for (const layer of order) {
|
|
179
|
+
const policy = layers[layer];
|
|
180
|
+
if (policy)
|
|
181
|
+
composed.push(policy);
|
|
182
|
+
}
|
|
183
|
+
if (composed.length === 0)
|
|
184
|
+
return null;
|
|
185
|
+
if (composed.length === 1)
|
|
186
|
+
return composed[0];
|
|
187
|
+
return wrap(...composed);
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=policy-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-factory.js","sourceRoot":"","sources":["../../src/helpers/policy-factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Labels describing the request currently executing under a policy. */
|
|
2
|
+
export interface ResilienceRequestLabels {
|
|
3
|
+
readonly requestName: string;
|
|
4
|
+
readonly handlerName: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Runs a whole policy execution with the labels of the request that triggered it.
|
|
8
|
+
*
|
|
9
|
+
* Policies are cached per handler so that circuit-breaker and bulkhead state is
|
|
10
|
+
* shared across invocations, while telemetry callbacks report the request that
|
|
11
|
+
* is actually executing: an event handler registered for several event types
|
|
12
|
+
* labels each retry or break with the event that triggered it.
|
|
13
|
+
*
|
|
14
|
+
* The scope wraps the entire `policy.execute(...)` call rather than a single
|
|
15
|
+
* attempt, because Cockatiel raises `onRetry`, `onBreak` and friends from its
|
|
16
|
+
* own loop, outside the per-attempt callback.
|
|
17
|
+
*/
|
|
18
|
+
export declare function runWithResilienceRequest<T>(labels: ResilienceRequestLabels, callback: () => T): T;
|
|
19
|
+
/** Labels of the in-flight request, when one is executing under a policy. */
|
|
20
|
+
export declare function getResilienceRequestLabels(): ResilienceRequestLabels | undefined;
|
|
21
|
+
/** Runs one policy attempt with its effective signal bound to its async work. */
|
|
22
|
+
export declare function runWithResilienceAbortSignal<T>(signal: AbortSignal, callback: () => T): T;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the AbortSignal supplied by the active resilience policy, when called
|
|
25
|
+
* inside a pipeline invocation wrapped by {@link ResilienceBehavior}.
|
|
26
|
+
*
|
|
27
|
+
* This is primarily useful with cooperative timeouts: pass the signal to APIs
|
|
28
|
+
* that support cancellation (fetch, database clients, SDK calls, etc.) so the
|
|
29
|
+
* work can stop when Cockatiel requests cancellation.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const signal = getResilienceAbortSignal();
|
|
34
|
+
* const response = await fetch('https://api.example.com/data', { signal });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function getResilienceAbortSignal(): AbortSignal | undefined;
|
|
38
|
+
//# sourceMappingURL=resilience-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-context.d.ts","sourceRoot":"","sources":["../../src/helpers/resilience-context.ts"],"names":[],"mappings":"AAMA,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,EAAE,MAAM,CAAC,GAChB,CAAC,CAEH;AAED,6EAA6E;AAC7E,wBAAgB,0BAA0B,IACtC,uBAAuB,GACvB,SAAS,CAEZ;AAED,iFAAiF;AACjF,wBAAgB,4BAA4B,CAAC,CAAC,EAC5C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,CAAC,GAChB,CAAC,CAEH;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,IAAI,WAAW,GAAG,SAAS,CAElE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
+
const resilienceAttemptStore = new AsyncLocalStorage();
|
|
4
|
+
const resilienceRequestStore = new AsyncLocalStorage();
|
|
5
|
+
/**
|
|
6
|
+
* Runs a whole policy execution with the labels of the request that triggered it.
|
|
7
|
+
*
|
|
8
|
+
* Policies are cached per handler so that circuit-breaker and bulkhead state is
|
|
9
|
+
* shared across invocations, while telemetry callbacks report the request that
|
|
10
|
+
* is actually executing: an event handler registered for several event types
|
|
11
|
+
* labels each retry or break with the event that triggered it.
|
|
12
|
+
*
|
|
13
|
+
* The scope wraps the entire `policy.execute(...)` call rather than a single
|
|
14
|
+
* attempt, because Cockatiel raises `onRetry`, `onBreak` and friends from its
|
|
15
|
+
* own loop, outside the per-attempt callback.
|
|
16
|
+
*/
|
|
17
|
+
export function runWithResilienceRequest(labels, callback) {
|
|
18
|
+
return resilienceRequestStore.run(labels, callback);
|
|
19
|
+
}
|
|
20
|
+
/** Labels of the in-flight request, when one is executing under a policy. */
|
|
21
|
+
export function getResilienceRequestLabels() {
|
|
22
|
+
return resilienceRequestStore.getStore();
|
|
23
|
+
}
|
|
24
|
+
/** Runs one policy attempt with its effective signal bound to its async work. */
|
|
25
|
+
export function runWithResilienceAbortSignal(signal, callback) {
|
|
26
|
+
return resilienceAttemptStore.run(signal, callback);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Returns the AbortSignal supplied by the active resilience policy, when called
|
|
30
|
+
* inside a pipeline invocation wrapped by {@link ResilienceBehavior}.
|
|
31
|
+
*
|
|
32
|
+
* This is primarily useful with cooperative timeouts: pass the signal to APIs
|
|
33
|
+
* that support cancellation (fetch, database clients, SDK calls, etc.) so the
|
|
34
|
+
* work can stop when Cockatiel requests cancellation.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const signal = getResilienceAbortSignal();
|
|
39
|
+
* const response = await fetch('https://api.example.com/data', { signal });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function getResilienceAbortSignal() {
|
|
43
|
+
return resilienceAttemptStore.getStore();
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=resilience-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience-context.js","sourceRoot":"","sources":["../../src/helpers/resilience-context.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,sBAAsB,GAAG,IAAI,iBAAiB,EAAe,CAAC;AAQpE,MAAM,sBAAsB,GAAG,IAAI,iBAAiB,EAA2B,CAAC;AAEhF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAA+B,EAC/B,QAAiB;IAEjB,OAAO,sBAAsB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,0BAA0B;IAGxC,OAAO,sBAAsB,CAAC,QAAQ,EAAE,CAAC;AAC3C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,4BAA4B,CAC1C,MAAmB,EACnB,QAAiB;IAEjB,OAAO,sBAAsB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,sBAAsB,CAAC,QAAQ,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PipelineBehaviorTuple } from '@cqrs-ddd/pipeline';
|
|
2
|
+
import type { ResilienceBehaviorOptions } from '../interfaces/resilience-options.interface.js';
|
|
3
|
+
import { ResilienceBehavior } from '../resilience.behavior.js';
|
|
4
|
+
export type ResilienceIntentOptions = ResilienceBehaviorOptions & ({
|
|
5
|
+
retry: NonNullable<ResilienceBehaviorOptions['retry']>;
|
|
6
|
+
} | {
|
|
7
|
+
timeout: NonNullable<ResilienceBehaviorOptions['timeout']>;
|
|
8
|
+
} | {
|
|
9
|
+
bulkhead: NonNullable<ResilienceBehaviorOptions['bulkhead']>;
|
|
10
|
+
} | {
|
|
11
|
+
policy: NonNullable<ResilienceBehaviorOptions['policy']>;
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Returns a resilience behavior entry for `pipeline.wrap()` or `createPipeline({ globalBehaviors })`.
|
|
15
|
+
* @param options At least one policy, plus optional classification and telemetry.
|
|
16
|
+
* @returns The behavior class and options tuple. Runtime safety checks still apply:
|
|
17
|
+
* retries on commands/events require `retry.replaySafe: true`; configure `handle`
|
|
18
|
+
* to select retryable errors unless classification is supplied by the constructor defaults.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* @pipeline.wrap({ kind: 'command' }, resilience({
|
|
22
|
+
* handle: (error) => error instanceof TransientGatewayError,
|
|
23
|
+
* retry: { maxAttempts: 3, replaySafe: true },
|
|
24
|
+
* timeout: { duration: 5_000 },
|
|
25
|
+
* }))
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function resilience(options: ResilienceIntentOptions): PipelineBehaviorTuple<ResilienceBehavior, ResilienceBehaviorOptions>;
|
|
29
|
+
//# sourceMappingURL=resilience.intent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.intent.d.ts","sourceRoot":"","sources":["../../src/helpers/resilience.intent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,uBAAuB,GAAG,yBAAyB,GAC7D,CACI;IAAE,KAAK,EAAE,WAAW,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC,CAAA;CAAE,GAC1D;IAAE,OAAO,EAAE,WAAW,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC,CAAA;CAAE,GAC9D;IAAE,QAAQ,EAAE,WAAW,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC,CAAA;CAAE,GAChE;IAAE,MAAM,EAAE,WAAW,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAE,CAC/D,CAAC;AAEJ;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,uBAAuB,GAC/B,qBAAqB,CAAC,kBAAkB,EAAE,yBAAyB,CAAC,CAEtE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
import { ResilienceBehavior } from '../resilience.behavior.js';
|
|
3
|
+
/**
|
|
4
|
+
* Returns a resilience behavior entry for `pipeline.wrap()` or `createPipeline({ globalBehaviors })`.
|
|
5
|
+
* @param options At least one policy, plus optional classification and telemetry.
|
|
6
|
+
* @returns The behavior class and options tuple. Runtime safety checks still apply:
|
|
7
|
+
* retries on commands/events require `retry.replaySafe: true`; configure `handle`
|
|
8
|
+
* to select retryable errors unless classification is supplied by the constructor defaults.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* @pipeline.wrap({ kind: 'command' }, resilience({
|
|
12
|
+
* handle: (error) => error instanceof TransientGatewayError,
|
|
13
|
+
* retry: { maxAttempts: 3, replaySafe: true },
|
|
14
|
+
* timeout: { duration: 5_000 },
|
|
15
|
+
* }))
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function resilience(options) {
|
|
19
|
+
return [ResilienceBehavior, options];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=resilience.intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resilience.intent.js","sourceRoot":"","sources":["../../src/helpers/resilience.intent.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAItE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAU/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CACxB,OAAgC;IAEhC,OAAO,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { BrokenCircuitError, BulkheadRejectedError, CircuitState, IsolatedCircuitError, isBrokenCircuitError, isBulkheadRejectedError, isIsolatedCircuitError, isTaskCancelledError, TaskCancelledError, } from 'cockatiel';
|
|
2
|
+
export { ResilienceConfigurationError } from './errors/resilience-configuration.error.js';
|
|
3
|
+
export { ResiliencePolicyConfigurationError } from './errors/resilience-policy-configuration.error.js';
|
|
4
|
+
export { type AnyPolicy, buildResiliencePolicy, type PolicyBuildContext, } from './helpers/policy-factory.js';
|
|
5
|
+
export { type ResilienceIntentOptions, resilience, } from './helpers/resilience.intent.js';
|
|
6
|
+
export { getResilienceAbortSignal } from './helpers/resilience-context.js';
|
|
7
|
+
export type { BreakerStrategy, BulkheadOptions, CircuitBreakerOptions, FallbackOptions, HandlerResilienceLayer, JitterStrategy, ResilienceBehaviorOptions, ResilienceLayer, ResiliencePolicyOptions, ResilienceTelemetry, ResilienceTelemetryEvent, RetryBackoff, RetryOptions, RetryPolicyOptions, TimeoutOptions, TimeoutPolicyOptions, } from './interfaces/resilience-options.interface.js';
|
|
8
|
+
export { ResilienceBehavior } from './resilience.behavior.js';
|
|
9
|
+
export { ResiliencePolicies } from './resilience-policies.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,4BAA4B,EAAE,MAAM,4CAA4C,CAAC;AAC1F,OAAO,EAAE,kCAAkC,EAAE,MAAM,mDAAmD,CAAC;AACvG,OAAO,EACL,KAAK,SAAS,EACd,qBAAqB,EACrB,KAAK,kBAAkB,GACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,uBAAuB,EAC5B,UAAU,GACX,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,YAAY,EACV,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,yBAAyB,EACzB,eAAe,EACf,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,oBAAoB,GACrB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
2
|
+
// Re-export the most useful cockatiel error types & enums so consumers can
|
|
3
|
+
// detect resilience outcomes without importing cockatiel directly.
|
|
4
|
+
export { BrokenCircuitError, BulkheadRejectedError, CircuitState, IsolatedCircuitError, isBrokenCircuitError, isBulkheadRejectedError, isIsolatedCircuitError, isTaskCancelledError, TaskCancelledError, } from 'cockatiel';
|
|
5
|
+
export { ResilienceConfigurationError } from './errors/resilience-configuration.error.js';
|
|
6
|
+
export { ResiliencePolicyConfigurationError } from './errors/resilience-policy-configuration.error.js';
|
|
7
|
+
export { buildResiliencePolicy, } from './helpers/policy-factory.js';
|
|
8
|
+
export { resilience, } from './helpers/resilience.intent.js';
|
|
9
|
+
export { getResilienceAbortSignal } from './helpers/resilience-context.js';
|
|
10
|
+
export { ResilienceBehavior } from './resilience.behavior.js';
|
|
11
|
+
export { ResiliencePolicies } from './resilience-policies.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,2EAA2E;AAC3E,mEAAmE;AACnE,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,4BAA4B,EAAE,MAAM,4CAA4C,CAAC;AAC1F,OAAO,EAAE,kCAAkC,EAAE,MAAM,mDAAmD,CAAC;AACvG,OAAO,EAEL,qBAAqB,GAEtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,UAAU,GACX,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAmB3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
|