@autonomaai/service-utils 1.0.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/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +12 -0
- package/dist/env.js.map +1 -0
- package/dist/fastify.d.ts +15 -0
- package/dist/fastify.d.ts.map +1 -0
- package/dist/fastify.js +57 -0
- package/dist/fastify.js.map +1 -0
- package/dist/health.d.ts +17 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +15 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +22 -0
- package/dist/logger.js.map +1 -0
- package/dist/resilience/bulkhead.d.ts +95 -0
- package/dist/resilience/bulkhead.d.ts.map +1 -0
- package/dist/resilience/bulkhead.js +186 -0
- package/dist/resilience/bulkhead.js.map +1 -0
- package/dist/resilience/circuit-breaker.d.ts +111 -0
- package/dist/resilience/circuit-breaker.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker.js +267 -0
- package/dist/resilience/circuit-breaker.js.map +1 -0
- package/dist/resilience/index.d.ts +15 -0
- package/dist/resilience/index.d.ts.map +1 -0
- package/dist/resilience/index.js +15 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/resilience/rate-limiter.d.ts +115 -0
- package/dist/resilience/rate-limiter.d.ts.map +1 -0
- package/dist/resilience/rate-limiter.js +257 -0
- package/dist/resilience/rate-limiter.js.map +1 -0
- package/dist/resilience/retry.d.ts +63 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +190 -0
- package/dist/resilience/retry.js.map +1 -0
- package/dist/resilience/timeout.d.ts +62 -0
- package/dist/resilience/timeout.d.ts.map +1 -0
- package/dist/resilience/timeout.js +135 -0
- package/dist/resilience/timeout.js.map +1 -0
- package/dist/resilience/types.d.ts +163 -0
- package/dist/resilience/types.d.ts.map +1 -0
- package/dist/resilience/types.js +64 -0
- package/dist/resilience/types.js.map +1 -0
- package/package.json +52 -0
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ZodSchema } from 'zod';
|
|
2
|
+
export interface LoadEnvOptions<T> {
|
|
3
|
+
source?: NodeJS.ProcessEnv;
|
|
4
|
+
transform?: (data: T) => T;
|
|
5
|
+
}
|
|
6
|
+
export declare function loadValidatedEnv<T>(schema: ZodSchema<T>, options?: LoadEnvOptions<T>): T;
|
|
7
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhC,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAC3B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAYxF"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function loadValidatedEnv(schema, options) {
|
|
2
|
+
const source = options?.source ?? process.env;
|
|
3
|
+
const parsed = schema.safeParse(source);
|
|
4
|
+
if (!parsed.success) {
|
|
5
|
+
const issues = parsed.error.issues
|
|
6
|
+
.map((issue) => `${issue.path.join('.') || 'root'}: ${issue.message}`)
|
|
7
|
+
.join('; ');
|
|
8
|
+
throw new Error(`Invalid environment configuration: ${issues}`);
|
|
9
|
+
}
|
|
10
|
+
return options?.transform ? options.transform(parsed.data) : parsed.data;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,gBAAgB,CAAI,MAAoB,EAAE,OAA2B;IACnF,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAExC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;aAC/B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;aACrE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sCAAsC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FastifyInstance } from 'fastify';
|
|
2
|
+
export interface RequestMetricsOptions {
|
|
3
|
+
logLevel?: 'info' | 'debug';
|
|
4
|
+
}
|
|
5
|
+
export declare function applyRequestMetricsHooks(app: FastifyInstance, options?: RequestMetricsOptions): void;
|
|
6
|
+
export interface ErrorHandlerOptions {
|
|
7
|
+
exposeStack?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function attachGlobalErrorHandler(app: FastifyInstance, options?: ErrorHandlerOptions): void;
|
|
10
|
+
export interface ShutdownHook {
|
|
11
|
+
name: string;
|
|
12
|
+
close: () => Promise<void> | void;
|
|
13
|
+
}
|
|
14
|
+
export declare function registerGracefulShutdown(app: FastifyInstance, hooks?: ShutdownHook[]): void;
|
|
15
|
+
//# sourceMappingURL=fastify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../src/fastify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAIxE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC7B;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,qBAAqB,QAqB7F;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,QAiB3F;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,GAAE,YAAY,EAAO,QAiBxF"}
|
package/dist/fastify.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const START_TIME = Symbol('requestStartTime');
|
|
2
|
+
export function applyRequestMetricsHooks(app, options) {
|
|
3
|
+
const level = options?.logLevel ?? 'info';
|
|
4
|
+
app.addHook('onRequest', (request, _reply, done) => {
|
|
5
|
+
request[START_TIME] = process.hrtime.bigint();
|
|
6
|
+
done();
|
|
7
|
+
});
|
|
8
|
+
app.addHook('onResponse', (request, reply, done) => {
|
|
9
|
+
const started = request[START_TIME];
|
|
10
|
+
const durationMs = started ? Number((process.hrtime.bigint() - started) / BigInt(1e6)) : 0;
|
|
11
|
+
reply.header('X-Response-Time', `${durationMs}ms`);
|
|
12
|
+
app.log[level]({
|
|
13
|
+
method: request.method,
|
|
14
|
+
url: request.url,
|
|
15
|
+
statusCode: reply.statusCode,
|
|
16
|
+
duration: `${durationMs}ms`,
|
|
17
|
+
ip: request.ip
|
|
18
|
+
}, 'request completed');
|
|
19
|
+
done();
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function attachGlobalErrorHandler(app, options) {
|
|
23
|
+
app.setErrorHandler((error, request, reply) => {
|
|
24
|
+
app.log.error({
|
|
25
|
+
error: error.message,
|
|
26
|
+
stack: options?.exposeStack ? error.stack : undefined,
|
|
27
|
+
method: request.method,
|
|
28
|
+
url: request.url
|
|
29
|
+
}, 'request error');
|
|
30
|
+
const statusCode = error.statusCode ?? 500;
|
|
31
|
+
reply.status(statusCode).send({
|
|
32
|
+
error: {
|
|
33
|
+
message: statusCode === 500 ? 'Internal Server Error' : error.message,
|
|
34
|
+
statusCode
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function registerGracefulShutdown(app, hooks = []) {
|
|
40
|
+
const shutdown = async (signal) => {
|
|
41
|
+
app.log.warn({ signal }, 'received shutdown signal');
|
|
42
|
+
for (const hook of hooks) {
|
|
43
|
+
try {
|
|
44
|
+
await hook.close();
|
|
45
|
+
app.log.info({ resource: hook.name }, 'resource closed');
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
app.log.error({ resource: hook.name, error }, 'failed to close resource');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
await app.close();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
};
|
|
54
|
+
process.once('SIGINT', shutdown);
|
|
55
|
+
process.once('SIGTERM', shutdown);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../src/fastify.ts"],"names":[],"mappings":"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"}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type HealthStatus = 'healthy' | 'degraded' | 'critical';
|
|
2
|
+
export interface HealthHandlerOptions {
|
|
3
|
+
serviceName: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
build?: string;
|
|
6
|
+
getStatus?: () => Promise<HealthStatus> | HealthStatus;
|
|
7
|
+
getDetails?: () => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createHealthHandler(options: HealthHandlerOptions): () => Promise<{
|
|
10
|
+
details?: Record<string, unknown> | undefined;
|
|
11
|
+
status: HealthStatus;
|
|
12
|
+
service: string;
|
|
13
|
+
version: string;
|
|
14
|
+
build: string | undefined;
|
|
15
|
+
timestamp: string;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB;;;;;;;GAchE"}
|
package/dist/health.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function createHealthHandler(options) {
|
|
2
|
+
return async () => {
|
|
3
|
+
const status = options.getStatus ? await options.getStatus() : 'healthy';
|
|
4
|
+
const details = options.getDetails ? await options.getDetails() : undefined;
|
|
5
|
+
return {
|
|
6
|
+
status,
|
|
7
|
+
service: options.serviceName,
|
|
8
|
+
version: options.version ?? '1.0.0',
|
|
9
|
+
build: options.build,
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
...(details ? { details } : {})
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,OAAO,KAAK,IAAI,EAAE;QAChB,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE5E,OAAO;YACL,MAAM;YACN,OAAO,EAAE,OAAO,CAAC,WAAW;YAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO;YACnC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAsBzE"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
export function createServiceLogger(options) {
|
|
3
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
4
|
+
const enablePretty = typeof options.pretty === 'boolean' ? options.pretty : !isProduction;
|
|
5
|
+
const baseOptions = {
|
|
6
|
+
level: options.level ?? process.env.LOG_LEVEL ?? 'info',
|
|
7
|
+
base: {
|
|
8
|
+
service: options.serviceName
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
if (enablePretty) {
|
|
12
|
+
baseOptions.transport = {
|
|
13
|
+
target: 'pino-pretty',
|
|
14
|
+
options: {
|
|
15
|
+
colorize: true,
|
|
16
|
+
singleLine: true
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return pino(baseOptions);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAA+B,MAAM,MAAM,CAAC;AAQnD,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;IAC3D,MAAM,YAAY,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAE1F,MAAM,WAAW,GAAkB;QACjC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;QACvD,IAAI,EAAE;YACJ,OAAO,EAAE,OAAO,CAAC,WAAW;SAC7B;KACF,CAAC;IAEF,IAAI,YAAY,EAAE,CAAC;QACjB,WAAW,CAAC,SAAS,GAAG;YACtB,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE;gBACP,QAAQ,EAAE,IAAI;gBACd,UAAU,EAAE,IAAI;aACjB;SACF,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bulkhead Pattern
|
|
3
|
+
*
|
|
4
|
+
* Isolates failures by limiting concurrent executions.
|
|
5
|
+
* Prevents resource exhaustion by queuing excess requests.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const bulkhead = new Bulkhead({
|
|
10
|
+
* name: 'trading-operations',
|
|
11
|
+
* maxConcurrent: 10,
|
|
12
|
+
* maxQueued: 100,
|
|
13
|
+
* queueTimeout: 5000
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* try {
|
|
17
|
+
* const result = await bulkhead.execute(() => executeTrade());
|
|
18
|
+
* } catch (error) {
|
|
19
|
+
* if (error instanceof BulkheadFullError) {
|
|
20
|
+
* // Handle overload
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { BulkheadConfig } from './types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Bulkhead implementation for isolating concurrent executions
|
|
28
|
+
*/
|
|
29
|
+
export declare class Bulkhead {
|
|
30
|
+
private static instances;
|
|
31
|
+
private readonly config;
|
|
32
|
+
private activeCalls;
|
|
33
|
+
private queue;
|
|
34
|
+
private stats;
|
|
35
|
+
constructor(config: Partial<BulkheadConfig> & {
|
|
36
|
+
name: string;
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Execute a function through the bulkhead
|
|
40
|
+
*/
|
|
41
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Get bulkhead statistics
|
|
44
|
+
*/
|
|
45
|
+
getStats(): {
|
|
46
|
+
currentActive: number;
|
|
47
|
+
currentQueued: number;
|
|
48
|
+
totalCalls: number;
|
|
49
|
+
successfulCalls: number;
|
|
50
|
+
failedCalls: number;
|
|
51
|
+
rejectedCalls: number;
|
|
52
|
+
timedOutCalls: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Get current utilization (0-1)
|
|
56
|
+
*/
|
|
57
|
+
getUtilization(): number;
|
|
58
|
+
/**
|
|
59
|
+
* Get queue fill level (0-1)
|
|
60
|
+
*/
|
|
61
|
+
getQueueFillLevel(): number;
|
|
62
|
+
/**
|
|
63
|
+
* Run execution immediately
|
|
64
|
+
*/
|
|
65
|
+
private runExecution;
|
|
66
|
+
/**
|
|
67
|
+
* Queue execution for later
|
|
68
|
+
*/
|
|
69
|
+
private queueExecution;
|
|
70
|
+
/**
|
|
71
|
+
* Process queued items when capacity becomes available
|
|
72
|
+
*/
|
|
73
|
+
private processQueue;
|
|
74
|
+
/**
|
|
75
|
+
* Get stats for all bulkheads
|
|
76
|
+
*/
|
|
77
|
+
static getAllStats(): Map<string, ReturnType<Bulkhead['getStats']>>;
|
|
78
|
+
/**
|
|
79
|
+
* Get a bulkhead by name
|
|
80
|
+
*/
|
|
81
|
+
static get(name: string): Bulkhead | undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Decorator to apply bulkhead to a method
|
|
85
|
+
*/
|
|
86
|
+
export declare function withBulkhead(config: Partial<BulkheadConfig> & {
|
|
87
|
+
name: string;
|
|
88
|
+
}): <T extends (...args: any[]) => Promise<any>>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T>;
|
|
89
|
+
/**
|
|
90
|
+
* Create a bulkhead wrapper function
|
|
91
|
+
*/
|
|
92
|
+
export declare function createBulkhead(config: Partial<BulkheadConfig> & {
|
|
93
|
+
name: string;
|
|
94
|
+
}): <T>(fn: () => Promise<T>) => Promise<T>;
|
|
95
|
+
//# sourceMappingURL=bulkhead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulkhead.d.ts","sourceRoot":"","sources":["../../src/resilience/bulkhead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,cAAc,EAAqB,MAAM,YAAY,CAAC;AAe/D;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAoC;IAE5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAA8B;IAE3C,OAAO,CAAC,KAAK,CAQX;gBAEU,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAK9D;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBlD;;OAEG;IACH,QAAQ;;;;;;;;;IAQR;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;YACW,YAAY;IAkB1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAkBtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAQnE;;OAEG;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;CAG/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,IAG5D,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,EACzD,QAAQ,GAAG,EACX,aAAa,MAAM,EACnB,YAAY,uBAAuB,CAAC,CAAC,CAAC,gCAUzC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAGzC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bulkhead Pattern
|
|
3
|
+
*
|
|
4
|
+
* Isolates failures by limiting concurrent executions.
|
|
5
|
+
* Prevents resource exhaustion by queuing excess requests.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const bulkhead = new Bulkhead({
|
|
10
|
+
* name: 'trading-operations',
|
|
11
|
+
* maxConcurrent: 10,
|
|
12
|
+
* maxQueued: 100,
|
|
13
|
+
* queueTimeout: 5000
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* try {
|
|
17
|
+
* const result = await bulkhead.execute(() => executeTrade());
|
|
18
|
+
* } catch (error) {
|
|
19
|
+
* if (error instanceof BulkheadFullError) {
|
|
20
|
+
* // Handle overload
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { BulkheadFullError } from './types.js';
|
|
26
|
+
const DEFAULT_CONFIG = {
|
|
27
|
+
maxConcurrent: 10,
|
|
28
|
+
maxQueued: 100,
|
|
29
|
+
queueTimeout: 5000
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Bulkhead implementation for isolating concurrent executions
|
|
33
|
+
*/
|
|
34
|
+
export class Bulkhead {
|
|
35
|
+
static instances = new Map();
|
|
36
|
+
config;
|
|
37
|
+
activeCalls = 0;
|
|
38
|
+
queue = [];
|
|
39
|
+
stats = {
|
|
40
|
+
totalCalls: 0,
|
|
41
|
+
successfulCalls: 0,
|
|
42
|
+
failedCalls: 0,
|
|
43
|
+
rejectedCalls: 0,
|
|
44
|
+
timedOutCalls: 0,
|
|
45
|
+
currentActive: 0,
|
|
46
|
+
currentQueued: 0
|
|
47
|
+
};
|
|
48
|
+
constructor(config) {
|
|
49
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
50
|
+
Bulkhead.instances.set(this.config.name, this);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Execute a function through the bulkhead
|
|
54
|
+
*/
|
|
55
|
+
async execute(fn) {
|
|
56
|
+
this.stats.totalCalls++;
|
|
57
|
+
// Check if we can execute immediately
|
|
58
|
+
if (this.activeCalls < this.config.maxConcurrent) {
|
|
59
|
+
return this.runExecution(fn);
|
|
60
|
+
}
|
|
61
|
+
// Check if queue is full
|
|
62
|
+
if (this.queue.length >= this.config.maxQueued) {
|
|
63
|
+
this.stats.rejectedCalls++;
|
|
64
|
+
this.config.onReject?.();
|
|
65
|
+
throw new BulkheadFullError(this.config.name);
|
|
66
|
+
}
|
|
67
|
+
// Add to queue
|
|
68
|
+
return this.queueExecution(fn);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get bulkhead statistics
|
|
72
|
+
*/
|
|
73
|
+
getStats() {
|
|
74
|
+
return {
|
|
75
|
+
...this.stats,
|
|
76
|
+
currentActive: this.activeCalls,
|
|
77
|
+
currentQueued: this.queue.length
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get current utilization (0-1)
|
|
82
|
+
*/
|
|
83
|
+
getUtilization() {
|
|
84
|
+
return this.activeCalls / this.config.maxConcurrent;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get queue fill level (0-1)
|
|
88
|
+
*/
|
|
89
|
+
getQueueFillLevel() {
|
|
90
|
+
return this.queue.length / this.config.maxQueued;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Run execution immediately
|
|
94
|
+
*/
|
|
95
|
+
async runExecution(fn) {
|
|
96
|
+
this.activeCalls++;
|
|
97
|
+
this.stats.currentActive = this.activeCalls;
|
|
98
|
+
try {
|
|
99
|
+
const result = await fn();
|
|
100
|
+
this.stats.successfulCalls++;
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
this.stats.failedCalls++;
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
this.activeCalls--;
|
|
109
|
+
this.stats.currentActive = this.activeCalls;
|
|
110
|
+
this.processQueue();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Queue execution for later
|
|
115
|
+
*/
|
|
116
|
+
queueExecution(fn) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const timeout = setTimeout(() => {
|
|
119
|
+
// Remove from queue
|
|
120
|
+
const index = this.queue.findIndex(item => item.timeout === timeout);
|
|
121
|
+
if (index !== -1) {
|
|
122
|
+
this.queue.splice(index, 1);
|
|
123
|
+
this.stats.currentQueued = this.queue.length;
|
|
124
|
+
this.stats.timedOutCalls++;
|
|
125
|
+
reject(new Error(`Bulkhead queue timeout after ${this.config.queueTimeout}ms`));
|
|
126
|
+
}
|
|
127
|
+
}, this.config.queueTimeout);
|
|
128
|
+
this.queue.push({ fn, resolve, reject, timeout });
|
|
129
|
+
this.stats.currentQueued = this.queue.length;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Process queued items when capacity becomes available
|
|
134
|
+
*/
|
|
135
|
+
processQueue() {
|
|
136
|
+
if (this.queue.length === 0)
|
|
137
|
+
return;
|
|
138
|
+
if (this.activeCalls >= this.config.maxConcurrent)
|
|
139
|
+
return;
|
|
140
|
+
const item = this.queue.shift();
|
|
141
|
+
if (!item)
|
|
142
|
+
return;
|
|
143
|
+
this.stats.currentQueued = this.queue.length;
|
|
144
|
+
clearTimeout(item.timeout);
|
|
145
|
+
this.runExecution(item.fn)
|
|
146
|
+
.then(item.resolve)
|
|
147
|
+
.catch(item.reject);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get stats for all bulkheads
|
|
151
|
+
*/
|
|
152
|
+
static getAllStats() {
|
|
153
|
+
const stats = new Map();
|
|
154
|
+
for (const [name, bulkhead] of this.instances) {
|
|
155
|
+
stats.set(name, bulkhead.getStats());
|
|
156
|
+
}
|
|
157
|
+
return stats;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get a bulkhead by name
|
|
161
|
+
*/
|
|
162
|
+
static get(name) {
|
|
163
|
+
return this.instances.get(name);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Decorator to apply bulkhead to a method
|
|
168
|
+
*/
|
|
169
|
+
export function withBulkhead(config) {
|
|
170
|
+
const bulkhead = new Bulkhead(config);
|
|
171
|
+
return function (target, propertyKey, descriptor) {
|
|
172
|
+
const originalMethod = descriptor.value;
|
|
173
|
+
descriptor.value = async function (...args) {
|
|
174
|
+
return bulkhead.execute(() => originalMethod.apply(this, args));
|
|
175
|
+
};
|
|
176
|
+
return descriptor;
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Create a bulkhead wrapper function
|
|
181
|
+
*/
|
|
182
|
+
export function createBulkhead(config) {
|
|
183
|
+
const bulkhead = new Bulkhead(config);
|
|
184
|
+
return (fn) => bulkhead.execute(fn);
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=bulkhead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulkhead.js","sourceRoot":"","sources":["../../src/resilience/bulkhead.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker Pattern
|
|
3
|
+
*
|
|
4
|
+
* Prevents cascading failures by failing fast when a service is down.
|
|
5
|
+
* After a threshold of failures, the circuit opens and rejects requests
|
|
6
|
+
* for a recovery period before allowing test requests through.
|
|
7
|
+
*
|
|
8
|
+
* States:
|
|
9
|
+
* - CLOSED: Normal operation, requests flow through
|
|
10
|
+
* - OPEN: Service is down, fail immediately
|
|
11
|
+
* - HALF_OPEN: Testing if service recovered
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const breaker = new CircuitBreaker({
|
|
16
|
+
* name: 'exchange-api',
|
|
17
|
+
* failureThreshold: 5,
|
|
18
|
+
* recoveryTimeout: 30000,
|
|
19
|
+
* halfOpenMaxCalls: 3
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* try {
|
|
23
|
+
* const result = await breaker.execute(() => fetchData());
|
|
24
|
+
* } catch (error) {
|
|
25
|
+
* if (error instanceof CircuitBreakerOpenError) {
|
|
26
|
+
* // Use fallback
|
|
27
|
+
* return getCachedData();
|
|
28
|
+
* }
|
|
29
|
+
* throw error;
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
import { CircuitState, CircuitBreakerConfig, CircuitBreakerStats } from './types.js';
|
|
34
|
+
/**
|
|
35
|
+
* Circuit Breaker implementation
|
|
36
|
+
*/
|
|
37
|
+
export declare class CircuitBreaker {
|
|
38
|
+
private static instances;
|
|
39
|
+
private readonly config;
|
|
40
|
+
private state;
|
|
41
|
+
private failureCount;
|
|
42
|
+
private successCount;
|
|
43
|
+
private lastFailureTime?;
|
|
44
|
+
private halfOpenCalls;
|
|
45
|
+
private stats;
|
|
46
|
+
constructor(config: Partial<CircuitBreakerConfig> & {
|
|
47
|
+
name: string;
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Get current circuit state
|
|
51
|
+
*/
|
|
52
|
+
getState(): CircuitState;
|
|
53
|
+
/**
|
|
54
|
+
* Get circuit breaker statistics
|
|
55
|
+
*/
|
|
56
|
+
getStats(): CircuitBreakerStats;
|
|
57
|
+
/**
|
|
58
|
+
* Execute a function through the circuit breaker
|
|
59
|
+
*/
|
|
60
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Manually reset the circuit breaker
|
|
63
|
+
*/
|
|
64
|
+
reset(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Check if recovery should be attempted
|
|
67
|
+
*/
|
|
68
|
+
private shouldAttemptRecovery;
|
|
69
|
+
/**
|
|
70
|
+
* Handle successful execution
|
|
71
|
+
*/
|
|
72
|
+
private onSuccess;
|
|
73
|
+
/**
|
|
74
|
+
* Handle failed execution
|
|
75
|
+
*/
|
|
76
|
+
private onFailure;
|
|
77
|
+
/**
|
|
78
|
+
* Transition to a new state
|
|
79
|
+
*/
|
|
80
|
+
private transitionTo;
|
|
81
|
+
/**
|
|
82
|
+
* Check if error should be excluded from failure count
|
|
83
|
+
*/
|
|
84
|
+
private isExcludedError;
|
|
85
|
+
/**
|
|
86
|
+
* Lock mechanism using a promise-based queue for atomic operations
|
|
87
|
+
*/
|
|
88
|
+
private lockQueue;
|
|
89
|
+
private acquireLock;
|
|
90
|
+
/**
|
|
91
|
+
* Get stats for all circuit breakers (for monitoring)
|
|
92
|
+
*/
|
|
93
|
+
static getAllStats(): Map<string, CircuitBreakerStats>;
|
|
94
|
+
/**
|
|
95
|
+
* Get a circuit breaker by name
|
|
96
|
+
*/
|
|
97
|
+
static get(name: string): CircuitBreaker | undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Decorator to apply circuit breaker to a method
|
|
101
|
+
*/
|
|
102
|
+
export declare function withCircuitBreaker(config: Partial<CircuitBreakerConfig> & {
|
|
103
|
+
name: string;
|
|
104
|
+
}): <T extends (...args: any[]) => Promise<any>>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T>;
|
|
105
|
+
/**
|
|
106
|
+
* Create a circuit breaker wrapper function
|
|
107
|
+
*/
|
|
108
|
+
export declare function createCircuitBreaker(config: Partial<CircuitBreakerConfig> & {
|
|
109
|
+
name: string;
|
|
110
|
+
}): <T>(fn: () => Promise<T>) => Promise<T>;
|
|
111
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../src/resilience/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAUpB;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,SAAS,CAA0C;IAElE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,KAAK,CAMX;gBAEU,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAKpE;;OAEG;IACH,QAAQ,IAAI,YAAY;IAUxB;;OAEG;IACH,QAAQ,IAAI,mBAAmB;IAO/B;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAwClD;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAK7B;;OAEG;YACW,SAAS;IAkBvB;;OAEG;YACW,SAAS;IAuBvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,SAAS,CAAoC;YAEvC,WAAW;IAUzB;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAQtD;;OAEG;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;CAGrD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,IAGxE,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,EACzD,QAAQ,GAAG,EACX,aAAa,MAAM,EACnB,YAAY,uBAAuB,CAAC,CAAC,CAAC,gCAUzC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GACvD,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAGzC"}
|