actly 1.1.0 → 1.2.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/LICENSE +0 -0
- package/README.md +262 -232
- package/dist/core/act.cjs +505 -39
- package/dist/core/act.d.ts +81 -10
- package/dist/core/act.d.ts.map +1 -1
- package/dist/core/act.js +504 -40
- package/dist/core/act.js.map +1 -1
- package/dist/core/executor.cjs +21 -9
- package/dist/core/executor.d.ts +31 -6
- package/dist/core/executor.d.ts.map +1 -1
- package/dist/core/executor.js +21 -9
- package/dist/core/executor.js.map +1 -1
- package/dist/core/health.cjs +34 -0
- package/dist/core/health.d.ts +18 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +28 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/shutdown.cjs +60 -0
- package/dist/core/shutdown.d.ts +8 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +56 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/tenant.cjs +71 -0
- package/dist/core/tenant.d.ts +29 -0
- package/dist/core/tenant.d.ts.map +1 -0
- package/dist/core/tenant.js +68 -0
- package/dist/core/tenant.js.map +1 -0
- package/dist/errors.cjs +182 -0
- package/dist/errors.d.ts +151 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +171 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +56 -6
- package/dist/index.d.ts +22 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -4
- package/dist/index.js.map +1 -1
- package/dist/observability.cjs +45 -0
- package/dist/observability.d.ts +145 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +43 -0
- package/dist/observability.js.map +1 -0
- package/dist/policies/bulkhead.cjs +97 -0
- package/dist/policies/bulkhead.d.ts +3 -0
- package/dist/policies/bulkhead.d.ts.map +1 -0
- package/dist/policies/bulkhead.js +95 -0
- package/dist/policies/bulkhead.js.map +1 -0
- package/dist/policies/cache.cjs +223 -22
- package/dist/policies/cache.d.ts +42 -7
- package/dist/policies/cache.d.ts.map +1 -1
- package/dist/policies/cache.js +223 -22
- package/dist/policies/cache.js.map +1 -1
- package/dist/policies/circuitBreaker.cjs +85 -0
- package/dist/policies/circuitBreaker.d.ts +3 -0
- package/dist/policies/circuitBreaker.d.ts.map +1 -0
- package/dist/policies/circuitBreaker.js +83 -0
- package/dist/policies/circuitBreaker.js.map +1 -0
- package/dist/policies/dedupe.cjs +98 -21
- package/dist/policies/dedupe.d.ts +20 -13
- package/dist/policies/dedupe.d.ts.map +1 -1
- package/dist/policies/dedupe.js +98 -21
- package/dist/policies/dedupe.js.map +1 -1
- package/dist/policies/rateLimit.cjs +35 -0
- package/dist/policies/rateLimit.d.ts +3 -0
- package/dist/policies/rateLimit.d.ts.map +1 -0
- package/dist/policies/rateLimit.js +33 -0
- package/dist/policies/rateLimit.js.map +1 -0
- package/dist/policies/retry.cjs +103 -26
- package/dist/policies/retry.d.ts +25 -2
- package/dist/policies/retry.d.ts.map +1 -1
- package/dist/policies/retry.js +103 -26
- package/dist/policies/retry.js.map +1 -1
- package/dist/policies/timeout.cjs +78 -36
- package/dist/policies/timeout.d.ts +7 -18
- package/dist/policies/timeout.d.ts.map +1 -1
- package/dist/policies/timeout.js +84 -31
- package/dist/policies/timeout.js.map +1 -1
- package/dist/state/store.cjs +9 -2
- package/dist/state/store.d.ts +9 -0
- package/dist/state/store.d.ts.map +1 -1
- package/dist/state/store.js +9 -2
- package/dist/state/store.js.map +1 -1
- package/dist/stores/base.cjs +4 -4
- package/dist/stores/base.d.ts +32 -56
- package/dist/stores/base.d.ts.map +1 -1
- package/dist/stores/base.js +4 -4
- package/dist/stores/base.js.map +1 -1
- package/dist/stores/memory.cjs +161 -39
- package/dist/stores/memory.d.ts +64 -24
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +160 -39
- package/dist/stores/memory.js.map +1 -1
- package/dist/types/index.d.ts +315 -37
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/abort.cjs +212 -0
- package/dist/utils/abort.d.ts +79 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +206 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/abortPool.cjs +26 -0
- package/dist/utils/abortPool.d.ts +4 -0
- package/dist/utils/abortPool.d.ts.map +1 -0
- package/dist/utils/abortPool.js +22 -0
- package/dist/utils/abortPool.js.map +1 -0
- package/dist/utils/backoff.cjs +54 -0
- package/dist/utils/backoff.d.ts +14 -0
- package/dist/utils/backoff.d.ts.map +1 -0
- package/dist/utils/backoff.js +52 -0
- package/dist/utils/backoff.js.map +1 -0
- package/dist/utils/key.cjs +77 -0
- package/dist/utils/key.d.ts +29 -0
- package/dist/utils/key.d.ts.map +1 -0
- package/dist/utils/key.js +75 -0
- package/dist/utils/key.js.map +1 -0
- package/dist/utils/limits.cjs +40 -0
- package/dist/utils/limits.d.ts +39 -0
- package/dist/utils/limits.d.ts.map +1 -0
- package/dist/utils/limits.js +38 -0
- package/dist/utils/limits.js.map +1 -0
- package/dist/utils/sanitize.cjs +29 -0
- package/dist/utils/sanitize.d.ts +3 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +26 -0
- package/dist/utils/sanitize.js.map +1 -0
- package/dist/utils/validate.cjs +153 -0
- package/dist/utils/validate.d.ts +26 -0
- package/dist/utils/validate.d.ts.map +1 -0
- package/dist/utils/validate.js +141 -0
- package/dist/utils/validate.js.map +1 -0
- package/package.json +20 -37
package/dist/index.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// ─── Primary API ──────────────────────────────────────────────────────────────
|
|
2
|
+
export { act, invalidate, withStore, } from './core/act.js';
|
|
3
|
+
// ─── Execution engine (for custom policy chains) ──────────────────────────────
|
|
4
|
+
export { execute, REQUIRES_SYNC_STORE, } from './core/executor.js';
|
|
5
|
+
// ─── Stores ───────────────────────────────────────────────────────────────────
|
|
3
6
|
export { InMemoryStore } from './stores/memory.js';
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
export { isSyncStore, isAsyncStore, } from './stores/base.js';
|
|
8
|
+
// ─── Error classes ────────────────────────────────────────────────────────────
|
|
9
|
+
export { ActlyError, ActlyAbortError, TimeoutError, TotalTimeoutError, RetryExhaustedError, ValidationError, } from './errors.js';
|
|
10
|
+
// ─── Utilities (for custom policy authors) ────────────────────────────────────
|
|
11
|
+
export { anySignal, raceAbort, sleep, linkSignal, isAbortError, } from './utils/abort.js';
|
|
12
|
+
export { sanitizeKey, } from './utils/key.js';
|
|
13
|
+
export { computeDelay, } from './utils/backoff.js';
|
|
14
|
+
export { LIMITS, } from './utils/limits.js';
|
|
15
|
+
// ─── Hardening: new error classes ────────────────────────────────────────────
|
|
16
|
+
export { CircuitBreakerOpenError, BulkheadOverflowError, RateLimitError, } from './errors.js';
|
|
17
|
+
// ─── Hardening: health check & graceful shutdown ─────────────────────────────
|
|
18
|
+
export { createHealthCheck, } from './core/health.js';
|
|
19
|
+
export { drain, } from './core/shutdown.js';
|
|
20
|
+
// ─── Hardening: tenant isolation ─────────────────────────────────────────────
|
|
21
|
+
export { createTenantStore, createAsyncTenantStore, } from './core/tenant.js';
|
|
22
|
+
// ─── Hardening: error sanitization ───────────────────────────────────────────
|
|
23
|
+
export { sanitizeErrorMessage, sanitizeError, } from './utils/sanitize.js';
|
|
24
|
+
// ─── Hardening: AbortController pool ─────────────────────────────────────────
|
|
25
|
+
export { acquireController, releaseController, poolSize, } from './utils/abortPool.js';
|
|
6
26
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AAEjF,OAAO,EACL,GAAG,EACH,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAA;AAOtB,iFAAiF;AAEjF,OAAO,EACL,OAAO,EACP,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAE3B,iFAAiF;AAEjF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGlD,OAAO,EACL,WAAW,EACX,YAAY,GACb,MAAM,kBAAkB,CAAA;AAEzB,iFAAiF;AAEjF,OAAO,EACL,UAAU,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,GAChB,MAAM,aAAa,CAAA;AAgDpB,iFAAiF;AAEjF,OAAO,EACL,SAAS,EACT,SAAS,EACT,KAAK,EACL,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,MAAM,GACP,MAAM,mBAAmB,CAAA;AAI1B,gFAAgF;AAEhF,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,KAAK,GACN,MAAM,oBAAoB,CAAA;AAE3B,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,kBAAkB,CAAA;AAGzB,gFAAgF;AAEhF,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,qBAAqB,CAAA;AAE5B,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,GACT,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Observability hooks.
|
|
4
|
+
*
|
|
5
|
+
* Eight event types covering the entire lifecycle of an `act()` call.
|
|
6
|
+
*
|
|
7
|
+
* # Contract
|
|
8
|
+
*
|
|
9
|
+
* When `options.observability` is `null`/`undefined` (the common case),
|
|
10
|
+
* no event objects are allocated and no function calls are made. The
|
|
11
|
+
* hot path is a single null-check per policy decision.
|
|
12
|
+
*
|
|
13
|
+
* When hooks ARE registered, events are allocated lazily — only when the
|
|
14
|
+
* corresponding event actually fires. A cache hit doesn't allocate an
|
|
15
|
+
* `onRetry` event, for example.
|
|
16
|
+
*
|
|
17
|
+
* # Event shape
|
|
18
|
+
*
|
|
19
|
+
* Every event carries `key`, `traceId`, and `timestamp` for correlation.
|
|
20
|
+
* Event-specific fields are on the same object (no nesting) for flat
|
|
21
|
+
* destructuring in user code.
|
|
22
|
+
*
|
|
23
|
+
* # Ordering
|
|
24
|
+
*
|
|
25
|
+
* For a successful fresh call with retries:
|
|
26
|
+
* onAttempt (1) → onAttempt (2) → onRetry (1→2) → onAttempt (3) → onFinalSuccess
|
|
27
|
+
*
|
|
28
|
+
* For a cache hit:
|
|
29
|
+
* onCacheHit → onFinalSuccess
|
|
30
|
+
*
|
|
31
|
+
* For a dedupe joiner:
|
|
32
|
+
* onDedupeJoin → onFinalSuccess (or onFinalFailure)
|
|
33
|
+
*
|
|
34
|
+
* For a timeout:
|
|
35
|
+
* onAttempt → onTimeout → onFinalFailure
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.hasObservers = hasObservers;
|
|
39
|
+
/**
|
|
40
|
+
* Quick null-check helper. Policies call this once at decision points; if
|
|
41
|
+
* it returns false, no further observability work is done.
|
|
42
|
+
*/
|
|
43
|
+
function hasObservers(ctx) {
|
|
44
|
+
return ctx.observability != null;
|
|
45
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability hooks.
|
|
3
|
+
*
|
|
4
|
+
* Eight event types covering the entire lifecycle of an `act()` call.
|
|
5
|
+
*
|
|
6
|
+
* # Contract
|
|
7
|
+
*
|
|
8
|
+
* When `options.observability` is `null`/`undefined` (the common case),
|
|
9
|
+
* no event objects are allocated and no function calls are made. The
|
|
10
|
+
* hot path is a single null-check per policy decision.
|
|
11
|
+
*
|
|
12
|
+
* When hooks ARE registered, events are allocated lazily — only when the
|
|
13
|
+
* corresponding event actually fires. A cache hit doesn't allocate an
|
|
14
|
+
* `onRetry` event, for example.
|
|
15
|
+
*
|
|
16
|
+
* # Event shape
|
|
17
|
+
*
|
|
18
|
+
* Every event carries `key`, `traceId`, and `timestamp` for correlation.
|
|
19
|
+
* Event-specific fields are on the same object (no nesting) for flat
|
|
20
|
+
* destructuring in user code.
|
|
21
|
+
*
|
|
22
|
+
* # Ordering
|
|
23
|
+
*
|
|
24
|
+
* For a successful fresh call with retries:
|
|
25
|
+
* onAttempt (1) → onAttempt (2) → onRetry (1→2) → onAttempt (3) → onFinalSuccess
|
|
26
|
+
*
|
|
27
|
+
* For a cache hit:
|
|
28
|
+
* onCacheHit → onFinalSuccess
|
|
29
|
+
*
|
|
30
|
+
* For a dedupe joiner:
|
|
31
|
+
* onDedupeJoin → onFinalSuccess (or onFinalFailure)
|
|
32
|
+
*
|
|
33
|
+
* For a timeout:
|
|
34
|
+
* onAttempt → onTimeout → onFinalFailure
|
|
35
|
+
*/
|
|
36
|
+
import type { ActSource } from './types/index.js';
|
|
37
|
+
/** Stable discriminator for telemetry. */
|
|
38
|
+
export type ActlyEventType = 'attempt' | 'retry' | 'cache-hit' | 'cache-miss' | 'dedupe-join' | 'timeout' | 'final-success' | 'final-failure';
|
|
39
|
+
/** Common fields on every event. */
|
|
40
|
+
export interface ActlyEventBase {
|
|
41
|
+
/** The `key` passed to `act()`. */
|
|
42
|
+
readonly key: string;
|
|
43
|
+
/** Auto-generated trace ID (or user-supplied via `options.traceId`). */
|
|
44
|
+
readonly traceId: string;
|
|
45
|
+
/** Event timestamp (ms since epoch). */
|
|
46
|
+
readonly timestamp: number;
|
|
47
|
+
/** Discriminator for switch statements. */
|
|
48
|
+
readonly type: ActlyEventType;
|
|
49
|
+
}
|
|
50
|
+
export interface AttemptEvent extends ActlyEventBase {
|
|
51
|
+
readonly type: 'attempt';
|
|
52
|
+
/** 1-based attempt number. */
|
|
53
|
+
readonly attempt: number;
|
|
54
|
+
/** Duration of this attempt in ms (set after attempt settles). */
|
|
55
|
+
readonly durationMs?: number;
|
|
56
|
+
/** Error from this attempt, if it failed. */
|
|
57
|
+
readonly error?: unknown;
|
|
58
|
+
}
|
|
59
|
+
export interface RetryEvent extends ActlyEventBase {
|
|
60
|
+
readonly type: 'retry';
|
|
61
|
+
/** The attempt that just failed. */
|
|
62
|
+
readonly attempt: number;
|
|
63
|
+
/** The delay (ms) before the next attempt. */
|
|
64
|
+
readonly delayMs: number;
|
|
65
|
+
/** Error that triggered the retry. */
|
|
66
|
+
readonly error: unknown;
|
|
67
|
+
}
|
|
68
|
+
export interface CacheHitEvent extends ActlyEventBase {
|
|
69
|
+
readonly type: 'cache-hit';
|
|
70
|
+
/** Age of the cached value in ms. */
|
|
71
|
+
readonly ageMs: number;
|
|
72
|
+
}
|
|
73
|
+
export interface CacheMissEvent extends ActlyEventBase {
|
|
74
|
+
readonly type: 'cache-miss';
|
|
75
|
+
}
|
|
76
|
+
export interface DedupeJoinEvent extends ActlyEventBase {
|
|
77
|
+
readonly type: 'dedupe-join';
|
|
78
|
+
/** This caller's position in the joiner queue (1 = first joiner). */
|
|
79
|
+
readonly joinerPosition: number;
|
|
80
|
+
}
|
|
81
|
+
export interface TimeoutEvent extends ActlyEventBase {
|
|
82
|
+
readonly type: 'timeout';
|
|
83
|
+
/** Which deadline fired. */
|
|
84
|
+
readonly kind: 'per-attempt' | 'total';
|
|
85
|
+
/** The configured ms. */
|
|
86
|
+
readonly ms: number;
|
|
87
|
+
}
|
|
88
|
+
export interface FinalSuccessEvent extends ActlyEventBase {
|
|
89
|
+
readonly type: 'final-success';
|
|
90
|
+
/** Where the value came from. */
|
|
91
|
+
readonly source: ActSource;
|
|
92
|
+
/** Total attempts made (0 for cache hit). */
|
|
93
|
+
readonly attempts: number;
|
|
94
|
+
/** Total wall-clock duration of the act() call. */
|
|
95
|
+
readonly durationMs: number;
|
|
96
|
+
}
|
|
97
|
+
export interface FinalFailureEvent extends ActlyEventBase {
|
|
98
|
+
readonly type: 'final-failure';
|
|
99
|
+
/** Total attempts made. */
|
|
100
|
+
readonly attempts: number;
|
|
101
|
+
/** Total wall-clock duration of the act() call. */
|
|
102
|
+
readonly durationMs: number;
|
|
103
|
+
/** Stable reason for failure — use for telemetry tags. */
|
|
104
|
+
readonly failedBy: 'abort' | 'timeout' | 'total-timeout' | 'retry-exhausted' | 'fn-error' | 'validation';
|
|
105
|
+
/** The final error. */
|
|
106
|
+
readonly error: unknown;
|
|
107
|
+
}
|
|
108
|
+
export type ActlyEvent = AttemptEvent | RetryEvent | CacheHitEvent | CacheMissEvent | DedupeJoinEvent | TimeoutEvent | FinalSuccessEvent | FinalFailureEvent;
|
|
109
|
+
/**
|
|
110
|
+
* User-supplied observability hooks. All optional. When absent, zero
|
|
111
|
+
* overhead is incurred on the hot path.
|
|
112
|
+
*/
|
|
113
|
+
export interface ObservabilityHooks {
|
|
114
|
+
onAttempt?: (event: AttemptEvent) => void;
|
|
115
|
+
onRetry?: (event: RetryEvent) => void;
|
|
116
|
+
onCacheHit?: (event: CacheHitEvent) => void;
|
|
117
|
+
onCacheMiss?: (event: CacheMissEvent) => void;
|
|
118
|
+
onDedupeJoin?: (event: DedupeJoinEvent) => void;
|
|
119
|
+
onTimeout?: (event: TimeoutEvent) => void;
|
|
120
|
+
onFinalSuccess?: (event: FinalSuccessEvent) => void;
|
|
121
|
+
onFinalFailure?: (event: FinalFailureEvent) => void;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Internal: thread observability through the policy chain without changing
|
|
125
|
+
* every policy's signature. We attach it to `PolicyContext` as an optional
|
|
126
|
+
* field — policies that emit events check for its presence.
|
|
127
|
+
*
|
|
128
|
+
* `traceId` is also stored here so policies can include it in events.
|
|
129
|
+
*/
|
|
130
|
+
export interface ObservabilityContext {
|
|
131
|
+
traceId: string;
|
|
132
|
+
hooks: ObservabilityHooks;
|
|
133
|
+
/** Counter for dedupe joiner position. Per-key, but we approximate by call. */
|
|
134
|
+
joinerCounter: number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Quick null-check helper. Policies call this once at decision points; if
|
|
138
|
+
* it returns false, no further observability work is done.
|
|
139
|
+
*/
|
|
140
|
+
export declare function hasObservers(ctx: {
|
|
141
|
+
observability?: ObservabilityContext;
|
|
142
|
+
}): ctx is {
|
|
143
|
+
observability: ObservabilityContext;
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=observability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability hooks.
|
|
3
|
+
*
|
|
4
|
+
* Eight event types covering the entire lifecycle of an `act()` call.
|
|
5
|
+
*
|
|
6
|
+
* # Contract
|
|
7
|
+
*
|
|
8
|
+
* When `options.observability` is `null`/`undefined` (the common case),
|
|
9
|
+
* no event objects are allocated and no function calls are made. The
|
|
10
|
+
* hot path is a single null-check per policy decision.
|
|
11
|
+
*
|
|
12
|
+
* When hooks ARE registered, events are allocated lazily — only when the
|
|
13
|
+
* corresponding event actually fires. A cache hit doesn't allocate an
|
|
14
|
+
* `onRetry` event, for example.
|
|
15
|
+
*
|
|
16
|
+
* # Event shape
|
|
17
|
+
*
|
|
18
|
+
* Every event carries `key`, `traceId`, and `timestamp` for correlation.
|
|
19
|
+
* Event-specific fields are on the same object (no nesting) for flat
|
|
20
|
+
* destructuring in user code.
|
|
21
|
+
*
|
|
22
|
+
* # Ordering
|
|
23
|
+
*
|
|
24
|
+
* For a successful fresh call with retries:
|
|
25
|
+
* onAttempt (1) → onAttempt (2) → onRetry (1→2) → onAttempt (3) → onFinalSuccess
|
|
26
|
+
*
|
|
27
|
+
* For a cache hit:
|
|
28
|
+
* onCacheHit → onFinalSuccess
|
|
29
|
+
*
|
|
30
|
+
* For a dedupe joiner:
|
|
31
|
+
* onDedupeJoin → onFinalSuccess (or onFinalFailure)
|
|
32
|
+
*
|
|
33
|
+
* For a timeout:
|
|
34
|
+
* onAttempt → onTimeout → onFinalFailure
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Quick null-check helper. Policies call this once at decision points; if
|
|
38
|
+
* it returns false, no further observability work is done.
|
|
39
|
+
*/
|
|
40
|
+
export function hasObservers(ctx) {
|
|
41
|
+
return ctx.observability != null;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability.js","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AA0IH;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAA6C;IACxE,OAAO,GAAG,CAAC,aAAa,IAAI,IAAI,CAAA;AAClC,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bulkheadPolicy = bulkheadPolicy;
|
|
4
|
+
const executor_js_1 = require("../core/executor.js");
|
|
5
|
+
const errors_js_1 = require("../errors.js");
|
|
6
|
+
const NS = 'bulk:';
|
|
7
|
+
function getState(store, key) {
|
|
8
|
+
return store.get(NS + key) ?? { active: 0, queue: [] };
|
|
9
|
+
}
|
|
10
|
+
function setState(store, key, state) {
|
|
11
|
+
store.set(NS + key, state);
|
|
12
|
+
}
|
|
13
|
+
function bulkheadPolicy(opts) {
|
|
14
|
+
const maxConcurrent = Math.max(1, Math.floor(opts.maxConcurrent));
|
|
15
|
+
const queueTimeoutMs = opts.queueTimeoutMs ?? 0;
|
|
16
|
+
const applier = (fn, ctx) => {
|
|
17
|
+
const syncCtx = ctx;
|
|
18
|
+
return async (signal) => {
|
|
19
|
+
const key = syncCtx.key;
|
|
20
|
+
const acquireSlot = () => {
|
|
21
|
+
// If signal already aborted, reject immediately
|
|
22
|
+
if (signal.aborted)
|
|
23
|
+
return Promise.reject(signal.reason);
|
|
24
|
+
const state = getState(syncCtx.store, key);
|
|
25
|
+
if (state.active < maxConcurrent) {
|
|
26
|
+
state.active++;
|
|
27
|
+
setState(syncCtx.store, key, state);
|
|
28
|
+
return Promise.resolve();
|
|
29
|
+
}
|
|
30
|
+
if (queueTimeoutMs === 0) {
|
|
31
|
+
throw new errors_js_1.BulkheadOverflowError(key, maxConcurrent);
|
|
32
|
+
}
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const state2 = getState(syncCtx.store, key);
|
|
35
|
+
const entry = {
|
|
36
|
+
resolve,
|
|
37
|
+
reject,
|
|
38
|
+
signal,
|
|
39
|
+
};
|
|
40
|
+
// Remove entry from queue on signal abort
|
|
41
|
+
entry.onAbort = () => {
|
|
42
|
+
const s = getState(syncCtx.store, key);
|
|
43
|
+
const idx = s.queue.indexOf(entry);
|
|
44
|
+
if (idx >= 0) {
|
|
45
|
+
s.queue.splice(idx, 1);
|
|
46
|
+
setState(syncCtx.store, key, s);
|
|
47
|
+
}
|
|
48
|
+
if (entry.timer)
|
|
49
|
+
clearTimeout(entry.timer);
|
|
50
|
+
reject(signal.reason);
|
|
51
|
+
};
|
|
52
|
+
if (queueTimeoutMs > 0) {
|
|
53
|
+
entry.timer = setTimeout(() => {
|
|
54
|
+
const s = getState(syncCtx.store, key);
|
|
55
|
+
const idx = s.queue.indexOf(entry);
|
|
56
|
+
if (idx >= 0)
|
|
57
|
+
s.queue.splice(idx, 1);
|
|
58
|
+
setState(syncCtx.store, key, s);
|
|
59
|
+
signal.removeEventListener('abort', entry.onAbort);
|
|
60
|
+
reject(new errors_js_1.BulkheadOverflowError(key, maxConcurrent));
|
|
61
|
+
}, queueTimeoutMs);
|
|
62
|
+
}
|
|
63
|
+
signal.addEventListener('abort', entry.onAbort, { once: true });
|
|
64
|
+
state2.queue.push(entry);
|
|
65
|
+
setState(syncCtx.store, key, state2);
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
const releaseSlot = () => {
|
|
69
|
+
const state = getState(syncCtx.store, key);
|
|
70
|
+
state.active--;
|
|
71
|
+
if (state.queue.length > 0) {
|
|
72
|
+
const next = state.queue.shift();
|
|
73
|
+
state.active++;
|
|
74
|
+
if (next.timer)
|
|
75
|
+
clearTimeout(next.timer);
|
|
76
|
+
// Remove abort listener from the QUEUED caller's signal (not releaser's)
|
|
77
|
+
if (next.onAbort && next.signal) {
|
|
78
|
+
next.signal.removeEventListener('abort', next.onAbort);
|
|
79
|
+
}
|
|
80
|
+
next.resolve();
|
|
81
|
+
}
|
|
82
|
+
if (state.active < 0)
|
|
83
|
+
state.active = 0;
|
|
84
|
+
setState(syncCtx.store, key, state);
|
|
85
|
+
};
|
|
86
|
+
await acquireSlot();
|
|
87
|
+
try {
|
|
88
|
+
return await fn(signal);
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
releaseSlot();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
applier[executor_js_1.REQUIRES_SYNC_STORE] = true;
|
|
96
|
+
return applier;
|
|
97
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulkhead.d.ts","sourceRoot":"","sources":["../../src/policies/bulkhead.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,aAAa,EAAiB,eAAe,EAAE,MAAM,mBAAmB,CAAA;AA0B7F,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC,CAAC,CA0FzE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { REQUIRES_SYNC_STORE } from '../core/executor.js';
|
|
2
|
+
import { BulkheadOverflowError } from '../errors.js';
|
|
3
|
+
const NS = 'bulk:';
|
|
4
|
+
function getState(store, key) {
|
|
5
|
+
return store.get(NS + key) ?? { active: 0, queue: [] };
|
|
6
|
+
}
|
|
7
|
+
function setState(store, key, state) {
|
|
8
|
+
store.set(NS + key, state);
|
|
9
|
+
}
|
|
10
|
+
export function bulkheadPolicy(opts) {
|
|
11
|
+
const maxConcurrent = Math.max(1, Math.floor(opts.maxConcurrent));
|
|
12
|
+
const queueTimeoutMs = opts.queueTimeoutMs ?? 0;
|
|
13
|
+
const applier = (fn, ctx) => {
|
|
14
|
+
const syncCtx = ctx;
|
|
15
|
+
return async (signal) => {
|
|
16
|
+
const key = syncCtx.key;
|
|
17
|
+
const acquireSlot = () => {
|
|
18
|
+
// If signal already aborted, reject immediately
|
|
19
|
+
if (signal.aborted)
|
|
20
|
+
return Promise.reject(signal.reason);
|
|
21
|
+
const state = getState(syncCtx.store, key);
|
|
22
|
+
if (state.active < maxConcurrent) {
|
|
23
|
+
state.active++;
|
|
24
|
+
setState(syncCtx.store, key, state);
|
|
25
|
+
return Promise.resolve();
|
|
26
|
+
}
|
|
27
|
+
if (queueTimeoutMs === 0) {
|
|
28
|
+
throw new BulkheadOverflowError(key, maxConcurrent);
|
|
29
|
+
}
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const state2 = getState(syncCtx.store, key);
|
|
32
|
+
const entry = {
|
|
33
|
+
resolve,
|
|
34
|
+
reject,
|
|
35
|
+
signal,
|
|
36
|
+
};
|
|
37
|
+
// Remove entry from queue on signal abort
|
|
38
|
+
entry.onAbort = () => {
|
|
39
|
+
const s = getState(syncCtx.store, key);
|
|
40
|
+
const idx = s.queue.indexOf(entry);
|
|
41
|
+
if (idx >= 0) {
|
|
42
|
+
s.queue.splice(idx, 1);
|
|
43
|
+
setState(syncCtx.store, key, s);
|
|
44
|
+
}
|
|
45
|
+
if (entry.timer)
|
|
46
|
+
clearTimeout(entry.timer);
|
|
47
|
+
reject(signal.reason);
|
|
48
|
+
};
|
|
49
|
+
if (queueTimeoutMs > 0) {
|
|
50
|
+
entry.timer = setTimeout(() => {
|
|
51
|
+
const s = getState(syncCtx.store, key);
|
|
52
|
+
const idx = s.queue.indexOf(entry);
|
|
53
|
+
if (idx >= 0)
|
|
54
|
+
s.queue.splice(idx, 1);
|
|
55
|
+
setState(syncCtx.store, key, s);
|
|
56
|
+
signal.removeEventListener('abort', entry.onAbort);
|
|
57
|
+
reject(new BulkheadOverflowError(key, maxConcurrent));
|
|
58
|
+
}, queueTimeoutMs);
|
|
59
|
+
}
|
|
60
|
+
signal.addEventListener('abort', entry.onAbort, { once: true });
|
|
61
|
+
state2.queue.push(entry);
|
|
62
|
+
setState(syncCtx.store, key, state2);
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const releaseSlot = () => {
|
|
66
|
+
const state = getState(syncCtx.store, key);
|
|
67
|
+
state.active--;
|
|
68
|
+
if (state.queue.length > 0) {
|
|
69
|
+
const next = state.queue.shift();
|
|
70
|
+
state.active++;
|
|
71
|
+
if (next.timer)
|
|
72
|
+
clearTimeout(next.timer);
|
|
73
|
+
// Remove abort listener from the QUEUED caller's signal (not releaser's)
|
|
74
|
+
if (next.onAbort && next.signal) {
|
|
75
|
+
next.signal.removeEventListener('abort', next.onAbort);
|
|
76
|
+
}
|
|
77
|
+
next.resolve();
|
|
78
|
+
}
|
|
79
|
+
if (state.active < 0)
|
|
80
|
+
state.active = 0;
|
|
81
|
+
setState(syncCtx.store, key, state);
|
|
82
|
+
};
|
|
83
|
+
await acquireSlot();
|
|
84
|
+
try {
|
|
85
|
+
return await fn(signal);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
releaseSlot();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
applier[REQUIRES_SYNC_STORE] = true;
|
|
93
|
+
return applier;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=bulkhead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulkhead.js","sourceRoot":"","sources":["../../src/policies/bulkhead.ts"],"names":[],"mappings":"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"}
|