redeye-breaker 0.1.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.
@@ -0,0 +1,55 @@
1
+ import { CircuitBreakerState } from './types';
2
+ export interface Store {
3
+ get<T>(key: string): Promise<T | null>;
4
+ set<T>(key: string, value: T, ttlSeconds: number): Promise<void>;
5
+ del(key: string): Promise<void>;
6
+ /**
7
+ * Atomically increments the stored failure count for `key` and decides
8
+ * `isOpen` in a single round trip, so concurrent callers across instances
9
+ * can't race and lose an increment the way a plain get-then-set would.
10
+ *
11
+ * If omitted, the breaker falls back to a non-atomic get-then-set, which
12
+ * has a narrow race window under concurrent failures (see README).
13
+ */
14
+ recordFailureAtomic?(key: string, opts: {
15
+ ttlSeconds: number;
16
+ failureThreshold: number;
17
+ now: number;
18
+ }): Promise<CircuitBreakerState>;
19
+ /**
20
+ * Atomically claims a short-lived, exclusive "trial" slot for `key`
21
+ * (conceptually a SET-if-not-exists). Returns `true` if this call won the
22
+ * claim. Used to implement half-open: only the winner gets to make the
23
+ * trial call while a breaker is transitioning from open back to closed;
24
+ * everyone else stays blocked until the trial resolves.
25
+ *
26
+ * If omitted, the breaker falls back to letting every caller through
27
+ * once the reset window elapses (a thundering herd on recovery — see
28
+ * README).
29
+ */
30
+ claimTrial?(key: string, ttlSeconds: number): Promise<boolean>;
31
+ /**
32
+ * `strategy: 'errorRate'` only. Atomically folds one call's outcome into
33
+ * an EWMA failure-rate estimate and decides `isOpen` in a single round
34
+ * trip, the same atomicity guarantee `recordFailureAtomic` provides for
35
+ * the `'consecutive'` strategy. Called on every closed-phase call
36
+ * (success or failure), not just failures.
37
+ *
38
+ * `openedNow` distinguishes "this call is what tripped the breaker" from
39
+ * "the breaker was already open," so the caller can fire `onStateChange`
40
+ * exactly once per transition.
41
+ *
42
+ * If omitted, the breaker falls back to a non-atomic get-then-set.
43
+ */
44
+ recordOutcomeAtomic?(key: string, opts: {
45
+ success: boolean;
46
+ decay: number;
47
+ minimumCalls: number;
48
+ errorRateThreshold: number;
49
+ ttlSeconds: number;
50
+ now: number;
51
+ }): Promise<CircuitBreakerState & {
52
+ openedNow: boolean;
53
+ }>;
54
+ }
55
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;;;;;;OAOG;IACH,mBAAmB,CAAC,CAClB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,UAAU,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,CAClB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAC3H,OAAO,CAAC,mBAAmB,GAAG;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC1D"}
package/dist/store.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import type { Redis } from 'ioredis';
2
+ import { Store } from '../store';
3
+ import { CircuitBreakerState } from '../types';
4
+ /**
5
+ * Redis-backed Store implementation. Import this from
6
+ * `redeye/redis-store` so the core package has no hard dependency on
7
+ * `ioredis` — only consumers who use RedisStore need it installed.
8
+ *
9
+ * Implements all three optional atomic capabilities (`recordFailureAtomic`
10
+ * and `recordOutcomeAtomic` via Lua scripts, `claimTrial` via `SET ... NX`),
11
+ * so breakers backed by RedisStore get exact counting and real single-trial
12
+ * half-open behavior under both strategies instead of best-effort fallbacks.
13
+ */
14
+ export declare class RedisStore implements Store {
15
+ private readonly redis;
16
+ private readonly prefix;
17
+ constructor(redis: Redis, options?: {
18
+ keyPrefix?: string;
19
+ });
20
+ get<T>(key: string): Promise<T | null>;
21
+ set<T>(key: string, value: T, ttlSeconds: number): Promise<void>;
22
+ del(key: string): Promise<void>;
23
+ recordFailureAtomic(key: string, opts: {
24
+ ttlSeconds: number;
25
+ failureThreshold: number;
26
+ now: number;
27
+ }): Promise<CircuitBreakerState>;
28
+ recordOutcomeAtomic(key: string, opts: {
29
+ success: boolean;
30
+ decay: number;
31
+ minimumCalls: number;
32
+ errorRateThreshold: number;
33
+ ttlSeconds: number;
34
+ now: number;
35
+ }): Promise<CircuitBreakerState & {
36
+ openedNow: boolean;
37
+ }>;
38
+ claimTrial(key: string, ttlSeconds: number): Promise<boolean>;
39
+ }
40
+ //# sourceMappingURL=redis-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-store.d.ts","sourceRoot":"","sources":["../../src/stores/redis-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AA0F/C;;;;;;;;;GASG;AACH,qBAAa,UAAW,YAAW,KAAK;IAG1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFlC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEH,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO;IAIzE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAMtC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/B,mBAAmB,CACvB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC,mBAAmB,CAAC;IAYzB,mBAAmB,CACvB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAC3H,OAAO,CAAC,mBAAmB,GAAG;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAelD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAIpE"}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisStore = void 0;
4
+ /**
5
+ * Atomically increments the stored failure count and decides `isOpen` in one
6
+ * round trip: GET -> decode -> increment -> compute isOpen -> SET, all inside
7
+ * Redis's single-threaded script execution, so two instances failing at the
8
+ * same instant cannot race and lose an increment. Used by the `'consecutive'`
9
+ * strategy.
10
+ */
11
+ const RECORD_FAILURE_SCRIPT = `
12
+ local raw = redis.call('GET', KEYS[1])
13
+ local failures = 0
14
+ local openCount = 0
15
+ local errorRate = 0
16
+ local sampleCount = 0
17
+ if raw then
18
+ local ok, decoded = pcall(cjson.decode, raw)
19
+ if ok and decoded then
20
+ failures = tonumber(decoded.failures) or 0
21
+ openCount = tonumber(decoded.openCount) or 0
22
+ errorRate = tonumber(decoded.errorRate) or 0
23
+ sampleCount = tonumber(decoded.sampleCount) or 0
24
+ end
25
+ end
26
+ failures = failures + 1
27
+ local threshold = tonumber(ARGV[2])
28
+ local state = {
29
+ failures = failures,
30
+ lastFailure = tonumber(ARGV[3]),
31
+ isOpen = failures >= threshold,
32
+ openCount = openCount,
33
+ errorRate = errorRate,
34
+ sampleCount = sampleCount
35
+ }
36
+ redis.call('SET', KEYS[1], cjson.encode(state), 'EX', tonumber(ARGV[1]))
37
+ return cjson.encode(state)
38
+ `;
39
+ /**
40
+ * Atomically folds one call's outcome into an EWMA failure-rate estimate and
41
+ * decides `isOpen` in one round trip. Used by the `'errorRate'` strategy;
42
+ * called on every closed-phase call, not just failures. Also reports
43
+ * whether this specific call is what tripped the breaker (`openedNow`), so
44
+ * the caller can fire `onStateChange` exactly once per transition without a
45
+ * separate read.
46
+ */
47
+ const RECORD_OUTCOME_SCRIPT = `
48
+ local raw = redis.call('GET', KEYS[1])
49
+ local failures = 0
50
+ local openCount = 0
51
+ local errorRate = 0
52
+ local sampleCount = 0
53
+ local wasOpen = false
54
+ if raw then
55
+ local ok, decoded = pcall(cjson.decode, raw)
56
+ if ok and decoded then
57
+ failures = tonumber(decoded.failures) or 0
58
+ openCount = tonumber(decoded.openCount) or 0
59
+ errorRate = tonumber(decoded.errorRate) or 0
60
+ sampleCount = tonumber(decoded.sampleCount) or 0
61
+ wasOpen = decoded.isOpen or false
62
+ end
63
+ end
64
+ local decay = tonumber(ARGV[1])
65
+ local isFailure = tonumber(ARGV[2])
66
+ local minimumCalls = tonumber(ARGV[3])
67
+ local threshold = tonumber(ARGV[4])
68
+ local ttlSeconds = tonumber(ARGV[5])
69
+ local now = tonumber(ARGV[6])
70
+
71
+ errorRate = errorRate * decay + isFailure * (1 - decay)
72
+ sampleCount = sampleCount + 1
73
+ local isOpen = (sampleCount >= minimumCalls) and (errorRate >= threshold)
74
+
75
+ local state = {
76
+ failures = failures,
77
+ lastFailure = now,
78
+ isOpen = isOpen,
79
+ openCount = openCount,
80
+ errorRate = errorRate,
81
+ sampleCount = sampleCount
82
+ }
83
+ redis.call('SET', KEYS[1], cjson.encode(state), 'EX', ttlSeconds)
84
+
85
+ local result = {}
86
+ for k, v in pairs(state) do result[k] = v end
87
+ result.openedNow = isOpen and not wasOpen
88
+ return cjson.encode(result)
89
+ `;
90
+ /**
91
+ * Redis-backed Store implementation. Import this from
92
+ * `redeye/redis-store` so the core package has no hard dependency on
93
+ * `ioredis` — only consumers who use RedisStore need it installed.
94
+ *
95
+ * Implements all three optional atomic capabilities (`recordFailureAtomic`
96
+ * and `recordOutcomeAtomic` via Lua scripts, `claimTrial` via `SET ... NX`),
97
+ * so breakers backed by RedisStore get exact counting and real single-trial
98
+ * half-open behavior under both strategies instead of best-effort fallbacks.
99
+ */
100
+ class RedisStore {
101
+ constructor(redis, options = {}) {
102
+ this.redis = redis;
103
+ this.prefix = options.keyPrefix ?? '';
104
+ }
105
+ async get(key) {
106
+ const raw = await this.redis.get(this.prefix + key);
107
+ if (raw === null)
108
+ return null;
109
+ return JSON.parse(raw);
110
+ }
111
+ async set(key, value, ttlSeconds) {
112
+ await this.redis.set(this.prefix + key, JSON.stringify(value), 'EX', Math.max(1, Math.ceil(ttlSeconds)));
113
+ }
114
+ async del(key) {
115
+ await this.redis.del(this.prefix + key);
116
+ }
117
+ async recordFailureAtomic(key, opts) {
118
+ const raw = (await this.redis.eval(RECORD_FAILURE_SCRIPT, 1, this.prefix + key, Math.max(1, Math.ceil(opts.ttlSeconds)), opts.failureThreshold, opts.now));
119
+ return JSON.parse(raw);
120
+ }
121
+ async recordOutcomeAtomic(key, opts) {
122
+ const raw = (await this.redis.eval(RECORD_OUTCOME_SCRIPT, 1, this.prefix + key, opts.decay, opts.success ? 0 : 1, opts.minimumCalls, opts.errorRateThreshold, Math.max(1, Math.ceil(opts.ttlSeconds)), opts.now));
123
+ return JSON.parse(raw);
124
+ }
125
+ async claimTrial(key, ttlSeconds) {
126
+ const result = await this.redis.set(this.prefix + key, '1', 'EX', Math.max(1, Math.ceil(ttlSeconds)), 'NX');
127
+ return result === 'OK';
128
+ }
129
+ }
130
+ exports.RedisStore = RedisStore;
131
+ //# sourceMappingURL=redis-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-store.js","sourceRoot":"","sources":["../../src/stores/redis-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface CircuitBreakerState {
2
+ failures: number;
3
+ lastFailure: number;
4
+ isOpen: boolean;
5
+ /** Number of consecutive times a half-open trial has failed since the breaker last fully closed. Drives backoff growth. */
6
+ openCount: number;
7
+ /** `errorRate` strategy only: current EWMA estimate of the failure rate, 0-1. */
8
+ errorRate: number;
9
+ /** `errorRate` strategy only: number of calls folded into `errorRate` since the breaker last fully closed. */
10
+ sampleCount: number;
11
+ }
12
+ export interface CircuitMetrics {
13
+ totalCalls: number;
14
+ totalSuccesses: number;
15
+ totalFailures: number;
16
+ /** Calls rejected without invoking the wrapped function because the breaker was open. */
17
+ totalRejections: number;
18
+ /** Distributed mode only: store read/write failures encountered. */
19
+ totalStoreErrors: number;
20
+ }
21
+ export declare const CLOSED_STATE: CircuitBreakerState;
22
+ export declare const emptyMetrics: () => CircuitMetrics;
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,2HAA2H;IAC3H,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,8GAA8G;IAC9G,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,eAAe,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,YAAY,EAAE,mBAO1B,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,cAM9B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.emptyMetrics = exports.CLOSED_STATE = void 0;
4
+ exports.CLOSED_STATE = {
5
+ failures: 0,
6
+ lastFailure: 0,
7
+ isOpen: false,
8
+ openCount: 0,
9
+ errorRate: 0,
10
+ sampleCount: 0,
11
+ };
12
+ const emptyMetrics = () => ({
13
+ totalCalls: 0,
14
+ totalSuccesses: 0,
15
+ totalFailures: 0,
16
+ totalRejections: 0,
17
+ totalStoreErrors: 0,
18
+ });
19
+ exports.emptyMetrics = emptyMetrics;
20
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAsBa,QAAA,YAAY,GAAwB;IAC/C,QAAQ,EAAE,CAAC;IACX,WAAW,EAAE,CAAC;IACd,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,WAAW,EAAE,CAAC;CACf,CAAC;AAEK,MAAM,YAAY,GAAG,GAAmB,EAAE,CAAC,CAAC;IACjD,UAAU,EAAE,CAAC;IACb,cAAc,EAAE,CAAC;IACjB,aAAa,EAAE,CAAC;IAChB,eAAe,EAAE,CAAC;IAClB,gBAAgB,EAAE,CAAC;CACpB,CAAC,CAAC;AANU,QAAA,YAAY,gBAMtB"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "redeye-breaker",
3
+ "version": "0.1.0",
4
+ "description": "A circuit breaker for Node.js with an optional Redis-backed distributed mode, so breaker state can be shared across multiple app instances instead of being tracked per-process.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./redis-store": {
16
+ "types": "./dist/stores/redis-store.d.ts",
17
+ "default": "./dist/stores/redis-store.js"
18
+ }
19
+ },
20
+ "typesVersions": {
21
+ "*": {
22
+ "redis-store": ["dist/stores/redis-store.d.ts"]
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "test": "jest",
28
+ "test:integration": "jest --config jest.integration.config.js",
29
+ "lint": "tsc --noEmit",
30
+ "prepublishOnly": "npm run lint && npm run test && npm run build"
31
+ },
32
+ "keywords": [
33
+ "circuit-breaker",
34
+ "resilience",
35
+ "redis",
36
+ "distributed-systems",
37
+ "fault-tolerance",
38
+ "microservices"
39
+ ],
40
+ "author": "Laurels Echichinwo",
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/laurells/redeye.git"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/laurells/redeye/issues"
48
+ },
49
+ "homepage": "https://github.com/laurells/redeye#readme",
50
+ "peerDependencies": {
51
+ "ioredis": ">=5.0.0"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "ioredis": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "devDependencies": {
59
+ "@types/jest": "^29.5.12",
60
+ "@types/node": "^20.11.0",
61
+ "ioredis": "^5.4.1",
62
+ "jest": "^29.7.0",
63
+ "ts-jest": "^29.1.2",
64
+ "typescript": "^5.4.5"
65
+ },
66
+ "engines": {
67
+ "node": ">=18"
68
+ }
69
+ }