@takentrade/takentrade-libs 2.0.8 → 3.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/LICENSE +87 -0
- package/README.md +112 -743
- package/dist/common/health/health.controller.js +0 -2
- package/dist/common/index.d.ts +0 -2
- package/dist/common/index.js +0 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/metrics/circuit-breaker-metrics.service.d.ts +61 -0
- package/dist/metrics/circuit-breaker-metrics.service.js +149 -0
- package/dist/metrics/index.d.ts +5 -0
- package/dist/metrics/index.js +21 -0
- package/dist/metrics/metrics-registry.d.ts +50 -0
- package/dist/metrics/metrics-registry.js +156 -0
- package/dist/metrics/metrics-updater.d.ts +32 -0
- package/dist/metrics/metrics-updater.js +102 -0
- package/dist/metrics/metrics.controller.d.ts +11 -0
- package/dist/metrics/metrics.controller.js +32 -0
- package/dist/metrics/metrics.interface.d.ts +106 -0
- package/dist/metrics/metrics.interface.js +35 -0
- package/dist/metrics/metrics.module.d.ts +11 -0
- package/dist/metrics/metrics.module.js +39 -0
- package/dist/metrics/metrics.service.d.ts +50 -0
- package/dist/metrics/metrics.service.js +165 -0
- package/dist/resilience/circuit-breaker-event-handler.d.ts +16 -0
- package/dist/resilience/circuit-breaker-event-handler.js +70 -0
- package/dist/resilience/circuit-breaker-factory.d.ts +19 -0
- package/dist/resilience/circuit-breaker-factory.js +51 -0
- package/dist/resilience/circuit-breaker-stats.service.d.ts +37 -0
- package/dist/resilience/circuit-breaker-stats.service.js +69 -0
- package/dist/resilience/circuit-breaker.interface.d.ts +134 -0
- package/dist/resilience/circuit-breaker.interface.js +31 -0
- package/dist/{common/circuit-breaker → resilience}/circuit-breaker.module.js +1 -0
- package/dist/resilience/circuit-breaker.service.d.ts +119 -0
- package/dist/resilience/circuit-breaker.service.js +234 -0
- package/dist/resilience/index.d.ts +3 -0
- package/dist/resilience/index.js +19 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/dto/pagination.js +0 -6
- package/package.json +5 -2
- package/dist/common/circuit-breaker/circuit-breaker.service.d.ts +0 -13
- package/dist/common/circuit-breaker/circuit-breaker.service.js +0 -120
- package/dist/common/circuit-breaker/circuit-breaker.types.d.ts +0 -19
- package/dist/common/circuit-breaker/circuit-breaker.types.js +0 -9
- /package/dist/{common/circuit-breaker → resilience}/circuit-breaker.module.d.ts +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Counter, Gauge, Histogram, Summary, CounterConfiguration, GaugeConfiguration, HistogramConfiguration, SummaryConfiguration } from 'prom-client';
|
|
2
|
+
/**
|
|
3
|
+
* Metric types supported by the metrics service
|
|
4
|
+
*/
|
|
5
|
+
export declare enum MetricType {
|
|
6
|
+
COUNTER = "counter",
|
|
7
|
+
GAUGE = "gauge",
|
|
8
|
+
HISTOGRAM = "histogram",
|
|
9
|
+
SUMMARY = "summary"
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for the metrics module
|
|
13
|
+
*/
|
|
14
|
+
export interface MetricsModuleOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Enable default metrics collection (CPU, memory, etc.)
|
|
17
|
+
* @default true
|
|
18
|
+
*/
|
|
19
|
+
defaultMetrics?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Prefix for all metric names
|
|
22
|
+
* @default ''
|
|
23
|
+
*/
|
|
24
|
+
prefix?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Default labels to add to all metrics
|
|
27
|
+
* @default {}
|
|
28
|
+
*/
|
|
29
|
+
defaultLabels?: Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Interval for collecting default metrics (in milliseconds)
|
|
32
|
+
* @default 10000
|
|
33
|
+
*/
|
|
34
|
+
defaultMetricsInterval?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Enable circuit breaker metrics integration
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
circuitBreakerMetrics?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Counter metric configuration
|
|
43
|
+
*/
|
|
44
|
+
export interface CounterConfig extends Omit<CounterConfiguration<string>, 'registers'> {
|
|
45
|
+
name: string;
|
|
46
|
+
help: string;
|
|
47
|
+
labelNames?: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Gauge metric configuration
|
|
51
|
+
*/
|
|
52
|
+
export interface GaugeConfig extends Omit<GaugeConfiguration<string>, 'registers'> {
|
|
53
|
+
name: string;
|
|
54
|
+
help: string;
|
|
55
|
+
labelNames?: string[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Histogram metric configuration
|
|
59
|
+
*/
|
|
60
|
+
export interface HistogramConfig extends Omit<HistogramConfiguration<string>, 'registers'> {
|
|
61
|
+
name: string;
|
|
62
|
+
help: string;
|
|
63
|
+
labelNames?: string[];
|
|
64
|
+
buckets?: number[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Summary metric configuration
|
|
68
|
+
*/
|
|
69
|
+
export interface SummaryConfig extends Omit<SummaryConfiguration<string>, 'registers'> {
|
|
70
|
+
name: string;
|
|
71
|
+
help: string;
|
|
72
|
+
labelNames?: string[];
|
|
73
|
+
percentiles?: number[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Metric instance types
|
|
77
|
+
*/
|
|
78
|
+
export type MetricInstance = Counter<string> | Gauge<string> | Histogram<string> | Summary<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Metric registry entry
|
|
81
|
+
*/
|
|
82
|
+
export interface MetricEntry {
|
|
83
|
+
type: MetricType;
|
|
84
|
+
metric: MetricInstance;
|
|
85
|
+
config: CounterConfig | GaugeConfig | HistogramConfig | SummaryConfig;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Circuit breaker metric names
|
|
89
|
+
*/
|
|
90
|
+
export declare const CIRCUIT_BREAKER_METRICS: {
|
|
91
|
+
readonly STATE: "circuit_breaker_state";
|
|
92
|
+
readonly CALLS_TOTAL: "circuit_breaker_calls_total";
|
|
93
|
+
readonly LATENCY_SECONDS: "circuit_breaker_latency_seconds";
|
|
94
|
+
readonly FAILURES_TOTAL: "circuit_breaker_failures_total";
|
|
95
|
+
readonly SUCCESSES_TOTAL: "circuit_breaker_successes_total";
|
|
96
|
+
readonly REJECTS_TOTAL: "circuit_breaker_rejects_total";
|
|
97
|
+
readonly TIMEOUTS_TOTAL: "circuit_breaker_timeouts_total";
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Default histogram buckets for latency metrics (in seconds)
|
|
101
|
+
*/
|
|
102
|
+
export declare const DEFAULT_LATENCY_BUCKETS: number[];
|
|
103
|
+
/**
|
|
104
|
+
* Default summary percentiles
|
|
105
|
+
*/
|
|
106
|
+
export declare const DEFAULT_PERCENTILES: number[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_PERCENTILES = exports.DEFAULT_LATENCY_BUCKETS = exports.CIRCUIT_BREAKER_METRICS = exports.MetricType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Metric types supported by the metrics service
|
|
6
|
+
*/
|
|
7
|
+
var MetricType;
|
|
8
|
+
(function (MetricType) {
|
|
9
|
+
MetricType["COUNTER"] = "counter";
|
|
10
|
+
MetricType["GAUGE"] = "gauge";
|
|
11
|
+
MetricType["HISTOGRAM"] = "histogram";
|
|
12
|
+
MetricType["SUMMARY"] = "summary";
|
|
13
|
+
})(MetricType || (exports.MetricType = MetricType = {}));
|
|
14
|
+
/**
|
|
15
|
+
* Circuit breaker metric names
|
|
16
|
+
*/
|
|
17
|
+
exports.CIRCUIT_BREAKER_METRICS = {
|
|
18
|
+
STATE: 'circuit_breaker_state',
|
|
19
|
+
CALLS_TOTAL: 'circuit_breaker_calls_total',
|
|
20
|
+
LATENCY_SECONDS: 'circuit_breaker_latency_seconds',
|
|
21
|
+
FAILURES_TOTAL: 'circuit_breaker_failures_total',
|
|
22
|
+
SUCCESSES_TOTAL: 'circuit_breaker_successes_total',
|
|
23
|
+
REJECTS_TOTAL: 'circuit_breaker_rejects_total',
|
|
24
|
+
TIMEOUTS_TOTAL: 'circuit_breaker_timeouts_total',
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Default histogram buckets for latency metrics (in seconds)
|
|
28
|
+
*/
|
|
29
|
+
exports.DEFAULT_LATENCY_BUCKETS = [
|
|
30
|
+
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10,
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Default summary percentiles
|
|
34
|
+
*/
|
|
35
|
+
exports.DEFAULT_PERCENTILES = [0.5, 0.9, 0.95, 0.99];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { MetricsModuleOptions } from './metrics.interface';
|
|
3
|
+
export declare class MetricsModule {
|
|
4
|
+
/**
|
|
5
|
+
* Register the metrics module with options
|
|
6
|
+
*
|
|
7
|
+
* @param options - Module configuration options
|
|
8
|
+
* @returns Dynamic module
|
|
9
|
+
*/
|
|
10
|
+
static register(options?: MetricsModuleOptions): DynamicModule;
|
|
11
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var MetricsModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.MetricsModule = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const metrics_service_1 = require("./metrics.service");
|
|
13
|
+
const metrics_controller_1 = require("./metrics.controller");
|
|
14
|
+
let MetricsModule = MetricsModule_1 = class MetricsModule {
|
|
15
|
+
/**
|
|
16
|
+
* Register the metrics module with options
|
|
17
|
+
*
|
|
18
|
+
* @param options - Module configuration options
|
|
19
|
+
* @returns Dynamic module
|
|
20
|
+
*/
|
|
21
|
+
static register(options = {}) {
|
|
22
|
+
return {
|
|
23
|
+
module: MetricsModule_1,
|
|
24
|
+
providers: [
|
|
25
|
+
{
|
|
26
|
+
provide: metrics_service_1.MetricsService,
|
|
27
|
+
useValue: new metrics_service_1.MetricsService(options),
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
controllers: [metrics_controller_1.MetricsController],
|
|
31
|
+
exports: [metrics_service_1.MetricsService],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
exports.MetricsModule = MetricsModule;
|
|
36
|
+
exports.MetricsModule = MetricsModule = MetricsModule_1 = __decorate([
|
|
37
|
+
(0, common_1.Global)(),
|
|
38
|
+
(0, common_1.Module)({})
|
|
39
|
+
], MetricsModule);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import { Registry } from 'prom-client';
|
|
3
|
+
import { CounterConfig, GaugeConfig, HistogramConfig, SummaryConfig, MetricsModuleOptions } from './metrics.interface';
|
|
4
|
+
/**
|
|
5
|
+
* Prometheus Metrics Service
|
|
6
|
+
*
|
|
7
|
+
* Provides comprehensive metrics collection and exposure for monitoring
|
|
8
|
+
* and observability using Prometheus.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Register a counter
|
|
13
|
+
* this.metricsService.registerCounter({
|
|
14
|
+
* name: 'api_requests_total',
|
|
15
|
+
* help: 'Total API requests',
|
|
16
|
+
* labelNames: ['method', 'endpoint'],
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Increment counter
|
|
20
|
+
* this.metricsService.incrementCounter('api_requests_total', { method: 'GET', endpoint: '/users' });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class MetricsService implements OnModuleDestroy {
|
|
24
|
+
private readonly logger;
|
|
25
|
+
private readonly registry;
|
|
26
|
+
private readonly metricsRegistry;
|
|
27
|
+
private readonly metricsUpdater;
|
|
28
|
+
private defaultMetricsInterval?;
|
|
29
|
+
private options;
|
|
30
|
+
constructor(options?: MetricsModuleOptions);
|
|
31
|
+
registerCounter(config: CounterConfig): import("prom-client").Counter<string>;
|
|
32
|
+
registerGauge(config: GaugeConfig): import("prom-client").Gauge<string>;
|
|
33
|
+
registerHistogram(config: HistogramConfig): import("prom-client").Histogram<string>;
|
|
34
|
+
registerSummary(config: SummaryConfig): import("prom-client").Summary<string>;
|
|
35
|
+
incrementCounter(name: string, labels?: Record<string, string | number>, value?: number): void;
|
|
36
|
+
setGauge(name: string, value: number, labels?: Record<string, string | number>): void;
|
|
37
|
+
incrementGauge(name: string, labels?: Record<string, string | number>, value?: number): void;
|
|
38
|
+
decrementGauge(name: string, labels?: Record<string, string | number>, value?: number): void;
|
|
39
|
+
observeHistogram(name: string, value: number, labels?: Record<string, string | number>): void;
|
|
40
|
+
observeSummary(name: string, value: number, labels?: Record<string, string | number>): void;
|
|
41
|
+
getMetric(name: string): import("./metrics.interface").MetricEntry | undefined;
|
|
42
|
+
getMetrics(): Promise<string>;
|
|
43
|
+
getContentType(): string;
|
|
44
|
+
getRegistry(): Registry;
|
|
45
|
+
getMetricNames(): string[];
|
|
46
|
+
hasMetric(name: string): boolean;
|
|
47
|
+
resetMetrics(): void;
|
|
48
|
+
clearMetrics(): void;
|
|
49
|
+
onModuleDestroy(): Promise<void>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var MetricsService_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.MetricsService = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const prom_client_1 = require("prom-client");
|
|
13
|
+
const metrics_registry_1 = require("./metrics-registry");
|
|
14
|
+
const metrics_updater_1 = require("./metrics-updater");
|
|
15
|
+
/**
|
|
16
|
+
* Prometheus Metrics Service
|
|
17
|
+
*
|
|
18
|
+
* Provides comprehensive metrics collection and exposure for monitoring
|
|
19
|
+
* and observability using Prometheus.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Register a counter
|
|
24
|
+
* this.metricsService.registerCounter({
|
|
25
|
+
* name: 'api_requests_total',
|
|
26
|
+
* help: 'Total API requests',
|
|
27
|
+
* labelNames: ['method', 'endpoint'],
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Increment counter
|
|
31
|
+
* this.metricsService.incrementCounter('api_requests_total', { method: 'GET', endpoint: '/users' });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
let MetricsService = MetricsService_1 = class MetricsService {
|
|
35
|
+
logger = new common_1.Logger(MetricsService_1.name);
|
|
36
|
+
registry;
|
|
37
|
+
metricsRegistry;
|
|
38
|
+
metricsUpdater;
|
|
39
|
+
defaultMetricsInterval;
|
|
40
|
+
options;
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
this.options = {
|
|
43
|
+
defaultMetrics: true,
|
|
44
|
+
prefix: '',
|
|
45
|
+
defaultLabels: {},
|
|
46
|
+
defaultMetricsInterval: 10000,
|
|
47
|
+
circuitBreakerMetrics: true,
|
|
48
|
+
...options,
|
|
49
|
+
};
|
|
50
|
+
this.registry = new prom_client_1.Registry();
|
|
51
|
+
this.metricsRegistry = new metrics_registry_1.MetricsRegistry(this.registry, this.options.prefix);
|
|
52
|
+
this.metricsUpdater = new metrics_updater_1.MetricsUpdater();
|
|
53
|
+
// Set default labels
|
|
54
|
+
if (this.options.defaultLabels) {
|
|
55
|
+
this.registry.setDefaultLabels(this.options.defaultLabels);
|
|
56
|
+
}
|
|
57
|
+
// Collect default metrics
|
|
58
|
+
if (this.options.defaultMetrics) {
|
|
59
|
+
this.defaultMetricsInterval = (0, prom_client_1.collectDefaultMetrics)({
|
|
60
|
+
register: this.registry,
|
|
61
|
+
prefix: this.options.prefix,
|
|
62
|
+
});
|
|
63
|
+
this.logger.log('Default metrics collection enabled');
|
|
64
|
+
}
|
|
65
|
+
this.logger.log('Metrics service initialized');
|
|
66
|
+
}
|
|
67
|
+
// ==================== Registration Methods ====================
|
|
68
|
+
registerCounter(config) {
|
|
69
|
+
return this.metricsRegistry.registerCounter(config);
|
|
70
|
+
}
|
|
71
|
+
registerGauge(config) {
|
|
72
|
+
return this.metricsRegistry.registerGauge(config);
|
|
73
|
+
}
|
|
74
|
+
registerHistogram(config) {
|
|
75
|
+
return this.metricsRegistry.registerHistogram(config);
|
|
76
|
+
}
|
|
77
|
+
registerSummary(config) {
|
|
78
|
+
return this.metricsRegistry.registerSummary(config);
|
|
79
|
+
}
|
|
80
|
+
// ==================== Update Methods ====================
|
|
81
|
+
incrementCounter(name, labels, value = 1) {
|
|
82
|
+
const entry = this.metricsRegistry.getMetric(name);
|
|
83
|
+
if (!entry) {
|
|
84
|
+
throw new Error(`Counter '${name}' not found`);
|
|
85
|
+
}
|
|
86
|
+
this.metricsUpdater.incrementCounter(entry, labels, value);
|
|
87
|
+
}
|
|
88
|
+
setGauge(name, value, labels) {
|
|
89
|
+
const entry = this.metricsRegistry.getMetric(name);
|
|
90
|
+
if (!entry) {
|
|
91
|
+
throw new Error(`Gauge '${name}' not found`);
|
|
92
|
+
}
|
|
93
|
+
this.metricsUpdater.setGauge(entry, value, labels);
|
|
94
|
+
}
|
|
95
|
+
incrementGauge(name, labels, value = 1) {
|
|
96
|
+
const entry = this.metricsRegistry.getMetric(name);
|
|
97
|
+
if (!entry) {
|
|
98
|
+
throw new Error(`Gauge '${name}' not found`);
|
|
99
|
+
}
|
|
100
|
+
this.metricsUpdater.incrementGauge(entry, labels, value);
|
|
101
|
+
}
|
|
102
|
+
decrementGauge(name, labels, value = 1) {
|
|
103
|
+
const entry = this.metricsRegistry.getMetric(name);
|
|
104
|
+
if (!entry) {
|
|
105
|
+
throw new Error(`Gauge '${name}' not found`);
|
|
106
|
+
}
|
|
107
|
+
this.metricsUpdater.decrementGauge(entry, labels, value);
|
|
108
|
+
}
|
|
109
|
+
observeHistogram(name, value, labels) {
|
|
110
|
+
const entry = this.metricsRegistry.getMetric(name);
|
|
111
|
+
if (!entry) {
|
|
112
|
+
throw new Error(`Histogram '${name}' not found`);
|
|
113
|
+
}
|
|
114
|
+
this.metricsUpdater.observeHistogram(entry, value, labels);
|
|
115
|
+
}
|
|
116
|
+
observeSummary(name, value, labels) {
|
|
117
|
+
const entry = this.metricsRegistry.getMetric(name);
|
|
118
|
+
if (!entry) {
|
|
119
|
+
throw new Error(`Summary '${name}' not found`);
|
|
120
|
+
}
|
|
121
|
+
this.metricsUpdater.observeSummary(entry, value, labels);
|
|
122
|
+
}
|
|
123
|
+
// ==================== Query Methods ====================
|
|
124
|
+
getMetric(name) {
|
|
125
|
+
return this.metricsRegistry.getMetric(name);
|
|
126
|
+
}
|
|
127
|
+
async getMetrics() {
|
|
128
|
+
return this.registry.metrics();
|
|
129
|
+
}
|
|
130
|
+
getContentType() {
|
|
131
|
+
return this.registry.contentType;
|
|
132
|
+
}
|
|
133
|
+
getRegistry() {
|
|
134
|
+
return this.registry;
|
|
135
|
+
}
|
|
136
|
+
getMetricNames() {
|
|
137
|
+
return this.metricsRegistry.getMetricNames();
|
|
138
|
+
}
|
|
139
|
+
hasMetric(name) {
|
|
140
|
+
return this.metricsRegistry.hasMetric(name);
|
|
141
|
+
}
|
|
142
|
+
// ==================== Management Methods ====================
|
|
143
|
+
resetMetrics() {
|
|
144
|
+
this.registry.resetMetrics();
|
|
145
|
+
this.logger.log('All metrics reset');
|
|
146
|
+
}
|
|
147
|
+
clearMetrics() {
|
|
148
|
+
this.registry.clear();
|
|
149
|
+
this.metricsRegistry.clear();
|
|
150
|
+
this.logger.log('All metrics cleared');
|
|
151
|
+
}
|
|
152
|
+
// ==================== Lifecycle ====================
|
|
153
|
+
async onModuleDestroy() {
|
|
154
|
+
this.logger.log('Shutting down metrics service...');
|
|
155
|
+
if (this.defaultMetricsInterval) {
|
|
156
|
+
clearInterval(this.defaultMetricsInterval);
|
|
157
|
+
}
|
|
158
|
+
this.clearMetrics();
|
|
159
|
+
this.logger.log('Metrics service shut down');
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
exports.MetricsService = MetricsService;
|
|
163
|
+
exports.MetricsService = MetricsService = MetricsService_1 = __decorate([
|
|
164
|
+
(0, common_1.Injectable)()
|
|
165
|
+
], MetricsService);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import CircuitBreaker from 'opossum';
|
|
2
|
+
/**
|
|
3
|
+
* Circuit Breaker Event Handler
|
|
4
|
+
*
|
|
5
|
+
* Handles all circuit breaker events and provides logging
|
|
6
|
+
*/
|
|
7
|
+
export declare class CircuitBreakerEventHandler {
|
|
8
|
+
private readonly logger;
|
|
9
|
+
/**
|
|
10
|
+
* Set up event listeners for a circuit breaker
|
|
11
|
+
*
|
|
12
|
+
* @param breaker - Circuit breaker instance
|
|
13
|
+
* @param name - Circuit breaker name
|
|
14
|
+
*/
|
|
15
|
+
setupEventListeners(breaker: CircuitBreaker, name: string): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CircuitBreakerEventHandler = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const circuit_breaker_interface_1 = require("./circuit-breaker.interface");
|
|
6
|
+
/**
|
|
7
|
+
* Circuit Breaker Event Handler
|
|
8
|
+
*
|
|
9
|
+
* Handles all circuit breaker events and provides logging
|
|
10
|
+
*/
|
|
11
|
+
class CircuitBreakerEventHandler {
|
|
12
|
+
logger = new common_1.Logger(CircuitBreakerEventHandler.name);
|
|
13
|
+
/**
|
|
14
|
+
* Set up event listeners for a circuit breaker
|
|
15
|
+
*
|
|
16
|
+
* @param breaker - Circuit breaker instance
|
|
17
|
+
* @param name - Circuit breaker name
|
|
18
|
+
*/
|
|
19
|
+
setupEventListeners(breaker, name) {
|
|
20
|
+
// Success event
|
|
21
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.SUCCESS, (result, latency) => {
|
|
22
|
+
this.logger.debug(`[${name}] Success - Latency: ${latency}ms`);
|
|
23
|
+
});
|
|
24
|
+
// Failure event
|
|
25
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.FAILURE, (error) => {
|
|
26
|
+
this.logger.warn(`[${name}] Failure - Error: ${error.message}`);
|
|
27
|
+
});
|
|
28
|
+
// Timeout event
|
|
29
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.TIMEOUT, () => {
|
|
30
|
+
this.logger.warn(`[${name}] Timeout - Request exceeded timeout threshold`);
|
|
31
|
+
});
|
|
32
|
+
// Reject event (circuit is open)
|
|
33
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.REJECT, () => {
|
|
34
|
+
this.logger.warn(`[${name}] Reject - Circuit is open, request rejected`);
|
|
35
|
+
});
|
|
36
|
+
// Circuit opened
|
|
37
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.OPEN, () => {
|
|
38
|
+
this.logger.error(`[${name}] Circuit OPENED - Too many failures detected`);
|
|
39
|
+
});
|
|
40
|
+
// Circuit closed
|
|
41
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.CLOSE, () => {
|
|
42
|
+
this.logger.log(`[${name}] Circuit CLOSED - Service recovered`);
|
|
43
|
+
});
|
|
44
|
+
// Circuit half-open
|
|
45
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.HALF_OPEN, () => {
|
|
46
|
+
this.logger.log(`[${name}] Circuit HALF-OPEN - Testing service recovery`);
|
|
47
|
+
});
|
|
48
|
+
// Fallback executed
|
|
49
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.FALLBACK, (result) => {
|
|
50
|
+
this.logger.debug(`[${name}] Fallback executed`);
|
|
51
|
+
});
|
|
52
|
+
// Semaphore locked (too many concurrent requests)
|
|
53
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.SEMAPHORE_LOCKED, () => {
|
|
54
|
+
this.logger.warn(`[${name}] Semaphore locked - Too many concurrent requests`);
|
|
55
|
+
});
|
|
56
|
+
// Health check failed
|
|
57
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.HEALTH_CHECK_FAILED, () => {
|
|
58
|
+
this.logger.warn(`[${name}] Health check failed`);
|
|
59
|
+
});
|
|
60
|
+
// Cache hit
|
|
61
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.CACHE_HIT, () => {
|
|
62
|
+
this.logger.debug(`[${name}] Cache hit`);
|
|
63
|
+
});
|
|
64
|
+
// Cache miss
|
|
65
|
+
breaker.on(circuit_breaker_interface_1.CircuitBreakerEvent.CACHE_MISS, () => {
|
|
66
|
+
this.logger.debug(`[${name}] Cache miss`);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.CircuitBreakerEventHandler = CircuitBreakerEventHandler;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CircuitBreakerOptions, CircuitBreakerInstance } from './circuit-breaker.interface';
|
|
2
|
+
/**
|
|
3
|
+
* Circuit Breaker Factory
|
|
4
|
+
*
|
|
5
|
+
* Responsible for creating and configuring circuit breaker instances
|
|
6
|
+
*/
|
|
7
|
+
export declare class CircuitBreakerFactory {
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private readonly eventHandler;
|
|
10
|
+
/**
|
|
11
|
+
* Create a new circuit breaker instance
|
|
12
|
+
*
|
|
13
|
+
* @param name - Unique identifier for the circuit breaker
|
|
14
|
+
* @param action - The async function to be protected
|
|
15
|
+
* @param options - Circuit breaker configuration options
|
|
16
|
+
* @returns Circuit breaker instance
|
|
17
|
+
*/
|
|
18
|
+
create<T = any, R = any>(name: string, action: (...args: T[]) => Promise<R>, options?: CircuitBreakerOptions): CircuitBreakerInstance<T, R>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CircuitBreakerFactory = void 0;
|
|
7
|
+
const common_1 = require("@nestjs/common");
|
|
8
|
+
const opossum_1 = __importDefault(require("opossum"));
|
|
9
|
+
const circuit_breaker_event_handler_1 = require("./circuit-breaker-event-handler");
|
|
10
|
+
/**
|
|
11
|
+
* Circuit Breaker Factory
|
|
12
|
+
*
|
|
13
|
+
* Responsible for creating and configuring circuit breaker instances
|
|
14
|
+
*/
|
|
15
|
+
class CircuitBreakerFactory {
|
|
16
|
+
logger = new common_1.Logger(CircuitBreakerFactory.name);
|
|
17
|
+
eventHandler = new circuit_breaker_event_handler_1.CircuitBreakerEventHandler();
|
|
18
|
+
/**
|
|
19
|
+
* Create a new circuit breaker instance
|
|
20
|
+
*
|
|
21
|
+
* @param name - Unique identifier for the circuit breaker
|
|
22
|
+
* @param action - The async function to be protected
|
|
23
|
+
* @param options - Circuit breaker configuration options
|
|
24
|
+
* @returns Circuit breaker instance
|
|
25
|
+
*/
|
|
26
|
+
create(name, action, options = {}) {
|
|
27
|
+
const defaultOptions = {
|
|
28
|
+
timeout: 10000, // 10 seconds
|
|
29
|
+
errorThresholdPercentage: 50, // 50% error rate
|
|
30
|
+
resetTimeout: 30000, // 30 seconds
|
|
31
|
+
rollingCountTimeout: 10000, // 10 seconds
|
|
32
|
+
rollingCountBuckets: 10,
|
|
33
|
+
capacity: 100,
|
|
34
|
+
enableSnapshots: true,
|
|
35
|
+
volumeThreshold: 5, // Minimum number of requests before circuit can open
|
|
36
|
+
name,
|
|
37
|
+
...options,
|
|
38
|
+
};
|
|
39
|
+
const breaker = new opossum_1.default(action, defaultOptions);
|
|
40
|
+
// Set up event listeners for monitoring and logging
|
|
41
|
+
this.eventHandler.setupEventListeners(breaker, name);
|
|
42
|
+
const instance = {
|
|
43
|
+
breaker,
|
|
44
|
+
name,
|
|
45
|
+
options: defaultOptions,
|
|
46
|
+
};
|
|
47
|
+
this.logger.log(`Circuit breaker '${name}' created successfully`);
|
|
48
|
+
return instance;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.CircuitBreakerFactory = CircuitBreakerFactory;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import CircuitBreaker from 'opossum';
|
|
2
|
+
import { CircuitBreakerStats, CircuitState, CircuitBreakerInstance } from './circuit-breaker.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Circuit Breaker Statistics Service
|
|
5
|
+
*
|
|
6
|
+
* Handles statistics and state management for circuit breakers
|
|
7
|
+
*/
|
|
8
|
+
export declare class CircuitBreakerStatsService {
|
|
9
|
+
/**
|
|
10
|
+
* Get statistics for a circuit breaker
|
|
11
|
+
*
|
|
12
|
+
* @param instance - Circuit breaker instance
|
|
13
|
+
* @returns Circuit breaker statistics
|
|
14
|
+
*/
|
|
15
|
+
getStats(instance: CircuitBreakerInstance): CircuitBreakerStats;
|
|
16
|
+
/**
|
|
17
|
+
* Get all circuit breaker statistics
|
|
18
|
+
*
|
|
19
|
+
* @param breakers - Map of circuit breaker instances
|
|
20
|
+
* @returns Map of circuit breaker names to their statistics
|
|
21
|
+
*/
|
|
22
|
+
getAllStats(breakers: Map<string, CircuitBreakerInstance>): Map<string, CircuitBreakerStats>;
|
|
23
|
+
/**
|
|
24
|
+
* Get the current state of a circuit breaker
|
|
25
|
+
*
|
|
26
|
+
* @param breaker - Circuit breaker instance
|
|
27
|
+
* @returns Current circuit state
|
|
28
|
+
*/
|
|
29
|
+
getState(breaker: CircuitBreaker): CircuitState;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a circuit breaker is open
|
|
32
|
+
*
|
|
33
|
+
* @param breaker - Circuit breaker instance
|
|
34
|
+
* @returns True if circuit is open
|
|
35
|
+
*/
|
|
36
|
+
isOpen(breaker: CircuitBreaker): boolean;
|
|
37
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CircuitBreakerStatsService = void 0;
|
|
4
|
+
const circuit_breaker_interface_1 = require("./circuit-breaker.interface");
|
|
5
|
+
/**
|
|
6
|
+
* Circuit Breaker Statistics Service
|
|
7
|
+
*
|
|
8
|
+
* Handles statistics and state management for circuit breakers
|
|
9
|
+
*/
|
|
10
|
+
class CircuitBreakerStatsService {
|
|
11
|
+
/**
|
|
12
|
+
* Get statistics for a circuit breaker
|
|
13
|
+
*
|
|
14
|
+
* @param instance - Circuit breaker instance
|
|
15
|
+
* @returns Circuit breaker statistics
|
|
16
|
+
*/
|
|
17
|
+
getStats(instance) {
|
|
18
|
+
const stats = instance.breaker.stats;
|
|
19
|
+
return {
|
|
20
|
+
fires: stats.fires,
|
|
21
|
+
failures: stats.failures,
|
|
22
|
+
successes: stats.successes,
|
|
23
|
+
rejects: stats.rejects,
|
|
24
|
+
timeouts: stats.timeouts,
|
|
25
|
+
cacheHits: stats.cacheHits,
|
|
26
|
+
cacheMisses: stats.cacheMisses,
|
|
27
|
+
semaphoreRejections: stats.semaphoreRejections,
|
|
28
|
+
percentiles: stats.percentiles,
|
|
29
|
+
latencyMean: stats.latencyMean,
|
|
30
|
+
latencyTimes: stats.latencyTimes,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get all circuit breaker statistics
|
|
35
|
+
*
|
|
36
|
+
* @param breakers - Map of circuit breaker instances
|
|
37
|
+
* @returns Map of circuit breaker names to their statistics
|
|
38
|
+
*/
|
|
39
|
+
getAllStats(breakers) {
|
|
40
|
+
const allStats = new Map();
|
|
41
|
+
for (const [name, instance] of breakers.entries()) {
|
|
42
|
+
allStats.set(name, this.getStats(instance));
|
|
43
|
+
}
|
|
44
|
+
return allStats;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the current state of a circuit breaker
|
|
48
|
+
*
|
|
49
|
+
* @param breaker - Circuit breaker instance
|
|
50
|
+
* @returns Current circuit state
|
|
51
|
+
*/
|
|
52
|
+
getState(breaker) {
|
|
53
|
+
if (breaker.opened)
|
|
54
|
+
return circuit_breaker_interface_1.CircuitState.OPEN;
|
|
55
|
+
if (breaker.halfOpen)
|
|
56
|
+
return circuit_breaker_interface_1.CircuitState.HALF_OPEN;
|
|
57
|
+
return circuit_breaker_interface_1.CircuitState.CLOSED;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if a circuit breaker is open
|
|
61
|
+
*
|
|
62
|
+
* @param breaker - Circuit breaker instance
|
|
63
|
+
* @returns True if circuit is open
|
|
64
|
+
*/
|
|
65
|
+
isOpen(breaker) {
|
|
66
|
+
return breaker.opened;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.CircuitBreakerStatsService = CircuitBreakerStatsService;
|