@fluyappgocore/commons-backend 1.0.202
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/build/classes/BacklogManager.d.ts +129 -0
- package/build/classes/BacklogManager.js +417 -0
- package/build/classes/BacklogMonitor.d.ts +102 -0
- package/build/classes/BacklogMonitor.js +222 -0
- package/build/classes/HttpResponse.d.ts +7 -0
- package/build/classes/HttpResponse.js +13 -0
- package/build/classes/index.d.ts +3 -0
- package/build/classes/index.js +15 -0
- package/build/dtos/file.dto.d.ts +5 -0
- package/build/dtos/file.dto.js +25 -0
- package/build/dtos/index.d.ts +1 -0
- package/build/dtos/index.js +13 -0
- package/build/events/BatchEnhancedListener.d.ts +106 -0
- package/build/events/BatchEnhancedListener.js +307 -0
- package/build/events/EnhancedListener.d.ts +75 -0
- package/build/events/EnhancedListener.js +185 -0
- package/build/events/baseListener.d.ts +19 -0
- package/build/events/baseListener.js +90 -0
- package/build/events/basePublisher.d.ts +14 -0
- package/build/events/basePublisher.js +84 -0
- package/build/events/config.d.ts +7 -0
- package/build/events/config.js +14 -0
- package/build/events/createClient.d.ts +38 -0
- package/build/events/createClient.js +416 -0
- package/build/events/index.d.ts +6 -0
- package/build/events/index.js +18 -0
- package/build/events/interfaces/agent.event.d.ts +7 -0
- package/build/events/interfaces/agent.event.js +2 -0
- package/build/events/interfaces/agentCrud.event.d.ts +7 -0
- package/build/events/interfaces/agentCrud.event.js +2 -0
- package/build/events/interfaces/agentTracking.event.d.ts +7 -0
- package/build/events/interfaces/agentTracking.event.js +2 -0
- package/build/events/interfaces/audit.event.d.ts +7 -0
- package/build/events/interfaces/audit.event.js +2 -0
- package/build/events/interfaces/branch.event.d.ts +7 -0
- package/build/events/interfaces/branch.event.js +2 -0
- package/build/events/interfaces/deleteTracking.event.d.ts +7 -0
- package/build/events/interfaces/deleteTracking.event.js +2 -0
- package/build/events/interfaces/department.event.d.ts +7 -0
- package/build/events/interfaces/department.event.js +2 -0
- package/build/events/interfaces/entity.event.d.ts +7 -0
- package/build/events/interfaces/entity.event.js +2 -0
- package/build/events/interfaces/index.d.ts +23 -0
- package/build/events/interfaces/index.js +35 -0
- package/build/events/interfaces/manualMatch.event.d.ts +7 -0
- package/build/events/interfaces/manualMatch.event.js +2 -0
- package/build/events/interfaces/match.event.d.ts +7 -0
- package/build/events/interfaces/match.event.js +2 -0
- package/build/events/interfaces/monitor.event.d.ts +7 -0
- package/build/events/interfaces/monitor.event.js +2 -0
- package/build/events/interfaces/notification.event.d.ts +7 -0
- package/build/events/interfaces/notification.event.js +2 -0
- package/build/events/interfaces/object.event.d.ts +7 -0
- package/build/events/interfaces/object.event.js +2 -0
- package/build/events/interfaces/payments.event.d.ts +7 -0
- package/build/events/interfaces/payments.event.js +2 -0
- package/build/events/interfaces/planning.event.d.ts +7 -0
- package/build/events/interfaces/planning.event.js +2 -0
- package/build/events/interfaces/service.event.d.ts +7 -0
- package/build/events/interfaces/service.event.js +2 -0
- package/build/events/interfaces/subscription.event.d.ts +7 -0
- package/build/events/interfaces/subscription.event.js +2 -0
- package/build/events/interfaces/ticket.event.d.ts +7 -0
- package/build/events/interfaces/ticket.event.js +2 -0
- package/build/events/interfaces/ticketNote.event.d.ts +7 -0
- package/build/events/interfaces/ticketNote.event.js +2 -0
- package/build/events/interfaces/ticketTracking.event.d.ts +7 -0
- package/build/events/interfaces/ticketTracking.event.js +2 -0
- package/build/events/interfaces/ticketxTopics.event.d.ts +7 -0
- package/build/events/interfaces/ticketxTopics.event.js +2 -0
- package/build/events/interfaces/topics.event.d.ts +7 -0
- package/build/events/interfaces/topics.event.js +2 -0
- package/build/events/interfaces/waitingList.event.d.ts +7 -0
- package/build/events/interfaces/waitingList.event.js +2 -0
- package/build/exceptions/AuthenticationTokenMissingException.d.ts +5 -0
- package/build/exceptions/AuthenticationTokenMissingException.js +27 -0
- package/build/exceptions/HttpException.d.ts +5 -0
- package/build/exceptions/HttpException.js +27 -0
- package/build/exceptions/MongoErrorException.d.ts +4 -0
- package/build/exceptions/MongoErrorException.js +27 -0
- package/build/exceptions/MulterException.d.ts +4 -0
- package/build/exceptions/MulterException.js +27 -0
- package/build/exceptions/QwizardException.d.ts +5 -0
- package/build/exceptions/QwizardException.js +27 -0
- package/build/exceptions/RecordingServerException.d.ts +5 -0
- package/build/exceptions/RecordingServerException.js +27 -0
- package/build/exceptions/UserNotFoundException.d.ts +4 -0
- package/build/exceptions/UserNotFoundException.js +27 -0
- package/build/exceptions/UserWithThatEmailAlreadyExistsException.d.ts +4 -0
- package/build/exceptions/UserWithThatEmailAlreadyExistsException.js +27 -0
- package/build/exceptions/WrongAnonymousAuthException.d.ts +5 -0
- package/build/exceptions/WrongAnonymousAuthException.js +27 -0
- package/build/exceptions/WrongAuthenticationTokenException.d.ts +5 -0
- package/build/exceptions/WrongAuthenticationTokenException.js +27 -0
- package/build/exceptions/WrongBusinessAuthException.d.ts +5 -0
- package/build/exceptions/WrongBusinessAuthException.js +27 -0
- package/build/exceptions/WrongCredentialsException.d.ts +4 -0
- package/build/exceptions/WrongCredentialsException.js +27 -0
- package/build/exceptions/WrongRoomException.d.ts +4 -0
- package/build/exceptions/WrongRoomException.js +27 -0
- package/build/exceptions/index.d.ts +16 -0
- package/build/exceptions/index.js +28 -0
- package/build/exceptions/invalidToken.exception.d.ts +4 -0
- package/build/exceptions/invalidToken.exception.js +27 -0
- package/build/exceptions/missingToken.exception.d.ts +4 -0
- package/build/exceptions/missingToken.exception.js +27 -0
- package/build/exceptions/wrongAuth.exception.d.ts +5 -0
- package/build/exceptions/wrongAuth.exception.js +27 -0
- package/build/index.d.ts +12 -0
- package/build/index.js +32 -0
- package/build/interfaces/controller.interface.d.ts +5 -0
- package/build/interfaces/controller.interface.js +2 -0
- package/build/interfaces/index.d.ts +3 -0
- package/build/interfaces/index.js +15 -0
- package/build/interfaces/requesWithUser.interface.d.ts +11 -0
- package/build/interfaces/requesWithUser.interface.js +2 -0
- package/build/interfaces/token.interface.d.ts +12 -0
- package/build/interfaces/token.interface.js +2 -0
- package/build/lib/ensureDatabase.d.ts +11 -0
- package/build/lib/ensureDatabase.js +97 -0
- package/build/lib/functions.d.ts +89 -0
- package/build/lib/functions.js +214 -0
- package/build/lib/helpers.d.ts +29 -0
- package/build/lib/helpers.js +33 -0
- package/build/lib/index.d.ts +4 -0
- package/build/lib/index.js +16 -0
- package/build/lib/logger.d.ts +2 -0
- package/build/lib/logger.js +41 -0
- package/build/middlewares/auth.middleware.d.ts +6 -0
- package/build/middlewares/auth.middleware.js +287 -0
- package/build/middlewares/error.middleware.d.ts +3 -0
- package/build/middlewares/error.middleware.js +14 -0
- package/build/middlewares/index.d.ts +3 -0
- package/build/middlewares/index.js +15 -0
- package/build/middlewares/validation.middleware.d.ts +2 -0
- package/build/middlewares/validation.middleware.js +22 -0
- package/package.json +45 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export declare type CircuitBreakerState = 'OPEN' | 'CLOSED' | 'HALF_OPEN';
|
|
2
|
+
export interface CircuitBreakerEvent {
|
|
3
|
+
listenerName: string;
|
|
4
|
+
state: CircuitBreakerState;
|
|
5
|
+
previousState: CircuitBreakerState;
|
|
6
|
+
timestamp: Date;
|
|
7
|
+
failureRate: number;
|
|
8
|
+
failedCount: number;
|
|
9
|
+
processedCount: number;
|
|
10
|
+
}
|
|
11
|
+
export declare type CircuitBreakerCallback = (event: CircuitBreakerEvent) => void | Promise<void>;
|
|
12
|
+
export interface BacklogConfig {
|
|
13
|
+
maxConcurrent: number;
|
|
14
|
+
rateLimitMs: number;
|
|
15
|
+
circuitBreakerThreshold: number;
|
|
16
|
+
circuitBreakerResetTime: number;
|
|
17
|
+
maxRetries: number;
|
|
18
|
+
backlogRecoveryBatchSize: number;
|
|
19
|
+
enableBacklogRecovery: boolean;
|
|
20
|
+
listenerName?: string;
|
|
21
|
+
onCircuitBreakerStateChange?: CircuitBreakerCallback;
|
|
22
|
+
}
|
|
23
|
+
export interface ProcessingStats {
|
|
24
|
+
processed: number;
|
|
25
|
+
failed: number;
|
|
26
|
+
retries: number;
|
|
27
|
+
circuitBreakerTrips: number;
|
|
28
|
+
lastProcessedAt: Date;
|
|
29
|
+
averageProcessingTime: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class BacklogManager {
|
|
32
|
+
private config;
|
|
33
|
+
private stats;
|
|
34
|
+
private processingQueue;
|
|
35
|
+
private activeProcessing;
|
|
36
|
+
private circuitBreakerOpen;
|
|
37
|
+
private circuitBreakerOpenTime?;
|
|
38
|
+
private lastProcessTime;
|
|
39
|
+
private processingTimes;
|
|
40
|
+
private circuitBreakerState;
|
|
41
|
+
constructor(config?: Partial<BacklogConfig>);
|
|
42
|
+
/**
|
|
43
|
+
* Procesa un mensaje con rate limiting y circuit breaker
|
|
44
|
+
*/
|
|
45
|
+
processMessage<T>(messageData: T, processor: (data: T) => Promise<void>, context?: string): Promise<boolean>;
|
|
46
|
+
/**
|
|
47
|
+
* Ejecuta el procesamiento con reintentos
|
|
48
|
+
*/
|
|
49
|
+
private executeWithRetry;
|
|
50
|
+
/**
|
|
51
|
+
* Procesa el siguiente mensaje en cola
|
|
52
|
+
*/
|
|
53
|
+
private processNextInQueue;
|
|
54
|
+
/**
|
|
55
|
+
* Actualiza métricas de éxito
|
|
56
|
+
*/
|
|
57
|
+
private updateSuccessMetrics;
|
|
58
|
+
/**
|
|
59
|
+
* Actualiza métricas de fallo
|
|
60
|
+
*/
|
|
61
|
+
private updateFailureMetrics;
|
|
62
|
+
/**
|
|
63
|
+
* Verifica si debe activar circuit breaker
|
|
64
|
+
*/
|
|
65
|
+
private checkCircuitBreaker;
|
|
66
|
+
/**
|
|
67
|
+
* Notifica cambio de estado del circuit breaker
|
|
68
|
+
*/
|
|
69
|
+
private notifyCircuitBreakerStateChange;
|
|
70
|
+
/**
|
|
71
|
+
* Verifica si debe resetear circuit breaker
|
|
72
|
+
*/
|
|
73
|
+
private checkCircuitBreakerReset;
|
|
74
|
+
/**
|
|
75
|
+
* Obtiene estadísticas actuales
|
|
76
|
+
*/
|
|
77
|
+
getStats(): ProcessingStats & {
|
|
78
|
+
queueSize: number;
|
|
79
|
+
activeProcessing: number;
|
|
80
|
+
circuitBreakerOpen: boolean;
|
|
81
|
+
config: BacklogConfig;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Resetea estadísticas
|
|
85
|
+
*/
|
|
86
|
+
resetStats(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Actualiza configuración en tiempo real
|
|
89
|
+
*/
|
|
90
|
+
updateConfig(newConfig: Partial<BacklogConfig>): void;
|
|
91
|
+
/**
|
|
92
|
+
* Utility sleep function
|
|
93
|
+
*/
|
|
94
|
+
private sleep;
|
|
95
|
+
/**
|
|
96
|
+
* Fuerza el cierre del circuit breaker (para testing/debugging)
|
|
97
|
+
*/
|
|
98
|
+
forceCircuitBreakerOpen(): void;
|
|
99
|
+
/**
|
|
100
|
+
* Fuerza la apertura del circuit breaker (para testing/debugging)
|
|
101
|
+
*/
|
|
102
|
+
forceCircuitBreakerClose(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Registra un callback para cambios de estado del circuit breaker
|
|
105
|
+
*/
|
|
106
|
+
onCircuitBreakerStateChange(callback: CircuitBreakerCallback): void;
|
|
107
|
+
/**
|
|
108
|
+
* Obtiene el estado actual del circuit breaker
|
|
109
|
+
*/
|
|
110
|
+
getCircuitBreakerState(): CircuitBreakerState;
|
|
111
|
+
/**
|
|
112
|
+
* Verifica si el BacklogManager está en capacidad máxima
|
|
113
|
+
* Usado para control de flujo en eachBatch
|
|
114
|
+
*/
|
|
115
|
+
isAtMaxCapacity(): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Obtiene la capacidad disponible actual
|
|
118
|
+
*/
|
|
119
|
+
getAvailableCapacity(): number;
|
|
120
|
+
/**
|
|
121
|
+
* Verifica si puede procesar un número específico de mensajes
|
|
122
|
+
*/
|
|
123
|
+
canProcessBatch(batchSize: number): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Espera hasta que haya capacidad disponible
|
|
126
|
+
* Usado en eachBatch para pausar el procesamiento
|
|
127
|
+
*/
|
|
128
|
+
waitForCapacity(minCapacity?: number, timeoutMs?: number): Promise<boolean>;
|
|
129
|
+
}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (_) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.BacklogManager = void 0;
|
|
51
|
+
var BacklogManager = /** @class */ (function () {
|
|
52
|
+
function BacklogManager(config) {
|
|
53
|
+
var _this = this;
|
|
54
|
+
if (config === void 0) { config = {}; }
|
|
55
|
+
this.processingQueue = [];
|
|
56
|
+
this.activeProcessing = 0;
|
|
57
|
+
this.circuitBreakerOpen = false;
|
|
58
|
+
this.lastProcessTime = 0;
|
|
59
|
+
this.processingTimes = [];
|
|
60
|
+
this.circuitBreakerState = 'CLOSED';
|
|
61
|
+
this.config = {
|
|
62
|
+
maxConcurrent: config.maxConcurrent || 5,
|
|
63
|
+
rateLimitMs: config.rateLimitMs || 100,
|
|
64
|
+
circuitBreakerThreshold: config.circuitBreakerThreshold || 10,
|
|
65
|
+
circuitBreakerResetTime: config.circuitBreakerResetTime || 60000,
|
|
66
|
+
maxRetries: config.maxRetries || 3,
|
|
67
|
+
backlogRecoveryBatchSize: config.backlogRecoveryBatchSize || 50,
|
|
68
|
+
enableBacklogRecovery: config.enableBacklogRecovery || true
|
|
69
|
+
};
|
|
70
|
+
this.stats = {
|
|
71
|
+
processed: 0,
|
|
72
|
+
failed: 0,
|
|
73
|
+
retries: 0,
|
|
74
|
+
circuitBreakerTrips: 0,
|
|
75
|
+
lastProcessedAt: new Date(),
|
|
76
|
+
averageProcessingTime: 0
|
|
77
|
+
};
|
|
78
|
+
// Auto-reset circuit breaker
|
|
79
|
+
setInterval(function () {
|
|
80
|
+
_this.checkCircuitBreakerReset();
|
|
81
|
+
}, 10000);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Procesa un mensaje con rate limiting y circuit breaker
|
|
85
|
+
*/
|
|
86
|
+
BacklogManager.prototype.processMessage = function (messageData, processor, context) {
|
|
87
|
+
if (context === void 0) { context = 'unknown'; }
|
|
88
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
89
|
+
var now, timeSinceLastProcess;
|
|
90
|
+
var _this = this;
|
|
91
|
+
return __generator(this, function (_a) {
|
|
92
|
+
switch (_a.label) {
|
|
93
|
+
case 0:
|
|
94
|
+
// Circuit breaker check
|
|
95
|
+
if (this.circuitBreakerOpen) {
|
|
96
|
+
console.log("\uD83D\uDEAB Circuit breaker open for " + context + ", skipping message");
|
|
97
|
+
return [2 /*return*/, false];
|
|
98
|
+
}
|
|
99
|
+
now = Date.now();
|
|
100
|
+
timeSinceLastProcess = now - this.lastProcessTime;
|
|
101
|
+
if (!(timeSinceLastProcess < this.config.rateLimitMs)) return [3 /*break*/, 2];
|
|
102
|
+
return [4 /*yield*/, this.sleep(this.config.rateLimitMs - timeSinceLastProcess)];
|
|
103
|
+
case 1:
|
|
104
|
+
_a.sent();
|
|
105
|
+
_a.label = 2;
|
|
106
|
+
case 2:
|
|
107
|
+
// Concurrency control
|
|
108
|
+
if (this.activeProcessing >= this.config.maxConcurrent) {
|
|
109
|
+
console.log("\u23F3 Max concurrency reached for " + context + ", queuing message");
|
|
110
|
+
return [2 /*return*/, new Promise(function (resolve) {
|
|
111
|
+
_this.processingQueue.push(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
112
|
+
var result;
|
|
113
|
+
return __generator(this, function (_a) {
|
|
114
|
+
switch (_a.label) {
|
|
115
|
+
case 0: return [4 /*yield*/, this.executeWithRetry(messageData, processor, context)];
|
|
116
|
+
case 1:
|
|
117
|
+
result = _a.sent();
|
|
118
|
+
resolve(result);
|
|
119
|
+
return [2 /*return*/];
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}); });
|
|
123
|
+
})];
|
|
124
|
+
}
|
|
125
|
+
return [4 /*yield*/, this.executeWithRetry(messageData, processor, context)];
|
|
126
|
+
case 3: return [2 /*return*/, _a.sent()];
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Ejecuta el procesamiento con reintentos
|
|
133
|
+
*/
|
|
134
|
+
BacklogManager.prototype.executeWithRetry = function (messageData, processor, context, attempt) {
|
|
135
|
+
if (attempt === void 0) { attempt = 1; }
|
|
136
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
137
|
+
var startTime, processingTime, error_1, processingTime, backoffDelay;
|
|
138
|
+
return __generator(this, function (_a) {
|
|
139
|
+
switch (_a.label) {
|
|
140
|
+
case 0:
|
|
141
|
+
this.activeProcessing++;
|
|
142
|
+
startTime = Date.now();
|
|
143
|
+
_a.label = 1;
|
|
144
|
+
case 1:
|
|
145
|
+
_a.trys.push([1, 3, 7, 8]);
|
|
146
|
+
return [4 /*yield*/, processor(messageData)];
|
|
147
|
+
case 2:
|
|
148
|
+
_a.sent();
|
|
149
|
+
processingTime = Date.now() - startTime;
|
|
150
|
+
this.updateSuccessMetrics(processingTime);
|
|
151
|
+
console.log("\u2705 " + context + " processed successfully (" + processingTime + "ms)");
|
|
152
|
+
return [2 /*return*/, true];
|
|
153
|
+
case 3:
|
|
154
|
+
error_1 = _a.sent();
|
|
155
|
+
processingTime = Date.now() - startTime;
|
|
156
|
+
console.error("\u274C " + context + " failed (attempt " + attempt + "/" + this.config.maxRetries + "):", error_1);
|
|
157
|
+
if (!(attempt < this.config.maxRetries)) return [3 /*break*/, 6];
|
|
158
|
+
this.stats.retries++;
|
|
159
|
+
backoffDelay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
|
|
160
|
+
return [4 /*yield*/, this.sleep(backoffDelay)];
|
|
161
|
+
case 4:
|
|
162
|
+
_a.sent();
|
|
163
|
+
return [4 /*yield*/, this.executeWithRetry(messageData, processor, context, attempt + 1)];
|
|
164
|
+
case 5: return [2 /*return*/, _a.sent()];
|
|
165
|
+
case 6:
|
|
166
|
+
// Max retries exceeded
|
|
167
|
+
this.updateFailureMetrics();
|
|
168
|
+
this.checkCircuitBreaker();
|
|
169
|
+
return [2 /*return*/, false];
|
|
170
|
+
case 7:
|
|
171
|
+
this.activeProcessing--;
|
|
172
|
+
this.lastProcessTime = Date.now();
|
|
173
|
+
this.processNextInQueue();
|
|
174
|
+
return [7 /*endfinally*/];
|
|
175
|
+
case 8: return [2 /*return*/];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Procesa el siguiente mensaje en cola
|
|
182
|
+
*/
|
|
183
|
+
BacklogManager.prototype.processNextInQueue = function () {
|
|
184
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
185
|
+
var nextProcessor;
|
|
186
|
+
return __generator(this, function (_a) {
|
|
187
|
+
switch (_a.label) {
|
|
188
|
+
case 0:
|
|
189
|
+
if (!(this.processingQueue.length > 0 && this.activeProcessing < this.config.maxConcurrent)) return [3 /*break*/, 2];
|
|
190
|
+
nextProcessor = this.processingQueue.shift();
|
|
191
|
+
if (!nextProcessor) return [3 /*break*/, 2];
|
|
192
|
+
return [4 /*yield*/, nextProcessor()];
|
|
193
|
+
case 1:
|
|
194
|
+
_a.sent();
|
|
195
|
+
_a.label = 2;
|
|
196
|
+
case 2: return [2 /*return*/];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Actualiza métricas de éxito
|
|
203
|
+
*/
|
|
204
|
+
BacklogManager.prototype.updateSuccessMetrics = function (processingTime) {
|
|
205
|
+
this.stats.processed++;
|
|
206
|
+
this.stats.lastProcessedAt = new Date();
|
|
207
|
+
// Mantener últimos 100 tiempos para promedio
|
|
208
|
+
this.processingTimes.push(processingTime);
|
|
209
|
+
if (this.processingTimes.length > 100) {
|
|
210
|
+
this.processingTimes.shift();
|
|
211
|
+
}
|
|
212
|
+
this.stats.averageProcessingTime =
|
|
213
|
+
this.processingTimes.reduce(function (a, b) { return a + b; }, 0) / this.processingTimes.length;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Actualiza métricas de fallo
|
|
217
|
+
*/
|
|
218
|
+
BacklogManager.prototype.updateFailureMetrics = function () {
|
|
219
|
+
this.stats.failed++;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Verifica si debe activar circuit breaker
|
|
223
|
+
*/
|
|
224
|
+
BacklogManager.prototype.checkCircuitBreaker = function () {
|
|
225
|
+
var recentFailureRate = this.stats.failed / (this.stats.processed + this.stats.failed);
|
|
226
|
+
console.log(recentFailureRate, this.stats.failed, this.stats.processed);
|
|
227
|
+
console.log(recentFailureRate > 0.5 && this.stats.failed >= this.config.circuitBreakerThreshold);
|
|
228
|
+
console.log(this.stats.failed >= this.config.circuitBreakerThreshold);
|
|
229
|
+
console.log(this.config);
|
|
230
|
+
if (recentFailureRate > 0.5 && this.stats.failed >= this.config.circuitBreakerThreshold) {
|
|
231
|
+
var previousState = this.circuitBreakerState;
|
|
232
|
+
this.circuitBreakerOpen = true;
|
|
233
|
+
this.circuitBreakerOpenTime = new Date();
|
|
234
|
+
this.circuitBreakerState = 'OPEN';
|
|
235
|
+
this.stats.circuitBreakerTrips++;
|
|
236
|
+
console.log("\uD83D\uDD34 Circuit breaker activated! Failure rate: " + (recentFailureRate * 100).toFixed(1) + "%");
|
|
237
|
+
// Notificar cambio de estado
|
|
238
|
+
this.notifyCircuitBreakerStateChange(previousState, 'OPEN', recentFailureRate);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* Notifica cambio de estado del circuit breaker
|
|
243
|
+
*/
|
|
244
|
+
BacklogManager.prototype.notifyCircuitBreakerStateChange = function (previousState, newState, failureRate) {
|
|
245
|
+
if (this.config.onCircuitBreakerStateChange && previousState !== newState) {
|
|
246
|
+
var event_1 = {
|
|
247
|
+
listenerName: this.config.listenerName || 'unknown',
|
|
248
|
+
state: newState,
|
|
249
|
+
previousState: previousState,
|
|
250
|
+
timestamp: new Date(),
|
|
251
|
+
failureRate: failureRate,
|
|
252
|
+
failedCount: this.stats.failed,
|
|
253
|
+
processedCount: this.stats.processed
|
|
254
|
+
};
|
|
255
|
+
try {
|
|
256
|
+
var result = this.config.onCircuitBreakerStateChange(event_1);
|
|
257
|
+
if (result instanceof Promise) {
|
|
258
|
+
result.catch(function (err) { return console.error('Error in circuit breaker callback:', err); });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
console.error('Error in circuit breaker callback:', err);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Verifica si debe resetear circuit breaker
|
|
268
|
+
*/
|
|
269
|
+
BacklogManager.prototype.checkCircuitBreakerReset = function () {
|
|
270
|
+
if (this.circuitBreakerOpen && this.circuitBreakerOpenTime) {
|
|
271
|
+
var timeSinceOpen = Date.now() - this.circuitBreakerOpenTime.getTime();
|
|
272
|
+
if (timeSinceOpen >= this.config.circuitBreakerResetTime) {
|
|
273
|
+
var previousState = this.circuitBreakerState;
|
|
274
|
+
var failureRate = this.stats.failed / (this.stats.processed + this.stats.failed);
|
|
275
|
+
this.circuitBreakerOpen = false;
|
|
276
|
+
this.circuitBreakerOpenTime = undefined;
|
|
277
|
+
this.circuitBreakerState = 'CLOSED';
|
|
278
|
+
// Reset failure stats for fresh start
|
|
279
|
+
this.stats.failed = Math.floor(this.stats.failed * 0.5);
|
|
280
|
+
console.log("\uD83D\uDFE2 Circuit breaker reset after " + timeSinceOpen + "ms");
|
|
281
|
+
// Notificar cambio de estado
|
|
282
|
+
this.notifyCircuitBreakerStateChange(previousState, 'CLOSED', failureRate);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* Obtiene estadísticas actuales
|
|
288
|
+
*/
|
|
289
|
+
BacklogManager.prototype.getStats = function () {
|
|
290
|
+
return __assign(__assign({}, this.stats), { queueSize: this.processingQueue.length, activeProcessing: this.activeProcessing, circuitBreakerOpen: this.circuitBreakerOpen, config: this.config });
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Resetea estadísticas
|
|
294
|
+
*/
|
|
295
|
+
BacklogManager.prototype.resetStats = function () {
|
|
296
|
+
this.stats = {
|
|
297
|
+
processed: 0,
|
|
298
|
+
failed: 0,
|
|
299
|
+
retries: 0,
|
|
300
|
+
circuitBreakerTrips: 0,
|
|
301
|
+
lastProcessedAt: new Date(),
|
|
302
|
+
averageProcessingTime: 0
|
|
303
|
+
};
|
|
304
|
+
this.processingTimes = [];
|
|
305
|
+
};
|
|
306
|
+
/**
|
|
307
|
+
* Actualiza configuración en tiempo real
|
|
308
|
+
*/
|
|
309
|
+
BacklogManager.prototype.updateConfig = function (newConfig) {
|
|
310
|
+
this.config = __assign(__assign({}, this.config), newConfig);
|
|
311
|
+
console.log("\uD83D\uDD27 BacklogManager config updated:", newConfig);
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* Utility sleep function
|
|
315
|
+
*/
|
|
316
|
+
BacklogManager.prototype.sleep = function (ms) {
|
|
317
|
+
return new Promise(function (resolve) { return setTimeout(resolve, ms); });
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Fuerza el cierre del circuit breaker (para testing/debugging)
|
|
321
|
+
*/
|
|
322
|
+
BacklogManager.prototype.forceCircuitBreakerOpen = function () {
|
|
323
|
+
var previousState = this.circuitBreakerState;
|
|
324
|
+
var failureRate = this.stats.failed / (this.stats.processed + this.stats.failed) || 0;
|
|
325
|
+
this.circuitBreakerOpen = true;
|
|
326
|
+
this.circuitBreakerOpenTime = new Date();
|
|
327
|
+
this.circuitBreakerState = 'OPEN';
|
|
328
|
+
this.stats.circuitBreakerTrips++;
|
|
329
|
+
this.notifyCircuitBreakerStateChange(previousState, 'OPEN', failureRate);
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* Fuerza la apertura del circuit breaker (para testing/debugging)
|
|
333
|
+
*/
|
|
334
|
+
BacklogManager.prototype.forceCircuitBreakerClose = function () {
|
|
335
|
+
var previousState = this.circuitBreakerState;
|
|
336
|
+
var failureRate = this.stats.failed / (this.stats.processed + this.stats.failed) || 0;
|
|
337
|
+
this.circuitBreakerOpen = false;
|
|
338
|
+
this.circuitBreakerOpenTime = undefined;
|
|
339
|
+
this.circuitBreakerState = 'CLOSED';
|
|
340
|
+
this.notifyCircuitBreakerStateChange(previousState, 'CLOSED', failureRate);
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* Registra un callback para cambios de estado del circuit breaker
|
|
344
|
+
*/
|
|
345
|
+
BacklogManager.prototype.onCircuitBreakerStateChange = function (callback) {
|
|
346
|
+
this.config.onCircuitBreakerStateChange = callback;
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* Obtiene el estado actual del circuit breaker
|
|
350
|
+
*/
|
|
351
|
+
BacklogManager.prototype.getCircuitBreakerState = function () {
|
|
352
|
+
return this.circuitBreakerState;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Verifica si el BacklogManager está en capacidad máxima
|
|
356
|
+
* Usado para control de flujo en eachBatch
|
|
357
|
+
*/
|
|
358
|
+
BacklogManager.prototype.isAtMaxCapacity = function () {
|
|
359
|
+
console.log(this.activeProcessing, this.config.maxConcurrent, this.processingQueue.length, this.config.backlogRecoveryBatchSize, this.circuitBreakerOpen);
|
|
360
|
+
console.log(this.activeProcessing >= this.config.maxConcurrent);
|
|
361
|
+
console.log(this.processingQueue.length >= this.config.backlogRecoveryBatchSize);
|
|
362
|
+
console.log(this.circuitBreakerOpen);
|
|
363
|
+
return this.activeProcessing >= this.config.maxConcurrent ||
|
|
364
|
+
this.processingQueue.length >= this.config.backlogRecoveryBatchSize ||
|
|
365
|
+
this.circuitBreakerOpen;
|
|
366
|
+
};
|
|
367
|
+
/**
|
|
368
|
+
* Obtiene la capacidad disponible actual
|
|
369
|
+
*/
|
|
370
|
+
BacklogManager.prototype.getAvailableCapacity = function () {
|
|
371
|
+
if (this.circuitBreakerOpen) {
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
var processingCapacity = Math.max(0, this.config.maxConcurrent - this.activeProcessing);
|
|
375
|
+
var queueCapacity = Math.max(0, this.config.backlogRecoveryBatchSize - this.processingQueue.length);
|
|
376
|
+
return Math.min(processingCapacity, queueCapacity);
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Verifica si puede procesar un número específico de mensajes
|
|
380
|
+
*/
|
|
381
|
+
BacklogManager.prototype.canProcessBatch = function (batchSize) {
|
|
382
|
+
return this.getAvailableCapacity() >= batchSize && !this.circuitBreakerOpen;
|
|
383
|
+
};
|
|
384
|
+
/**
|
|
385
|
+
* Espera hasta que haya capacidad disponible
|
|
386
|
+
* Usado en eachBatch para pausar el procesamiento
|
|
387
|
+
*/
|
|
388
|
+
BacklogManager.prototype.waitForCapacity = function (minCapacity, timeoutMs) {
|
|
389
|
+
if (minCapacity === void 0) { minCapacity = 1; }
|
|
390
|
+
if (timeoutMs === void 0) { timeoutMs = 30000; }
|
|
391
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
392
|
+
var startTime;
|
|
393
|
+
return __generator(this, function (_a) {
|
|
394
|
+
switch (_a.label) {
|
|
395
|
+
case 0:
|
|
396
|
+
startTime = Date.now();
|
|
397
|
+
_a.label = 1;
|
|
398
|
+
case 1:
|
|
399
|
+
if (!(this.getAvailableCapacity() < minCapacity && !this.circuitBreakerOpen)) return [3 /*break*/, 3];
|
|
400
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
401
|
+
console.warn("\u23F0 Timeout waiting for capacity after " + timeoutMs + "ms");
|
|
402
|
+
return [2 /*return*/, false];
|
|
403
|
+
}
|
|
404
|
+
// Esperar un poco antes de verificar de nuevo
|
|
405
|
+
return [4 /*yield*/, this.sleep(200)];
|
|
406
|
+
case 2:
|
|
407
|
+
// Esperar un poco antes de verificar de nuevo
|
|
408
|
+
_a.sent();
|
|
409
|
+
return [3 /*break*/, 1];
|
|
410
|
+
case 3: return [2 /*return*/, !this.circuitBreakerOpen];
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
};
|
|
415
|
+
return BacklogManager;
|
|
416
|
+
}());
|
|
417
|
+
exports.BacklogManager = BacklogManager;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export interface MonitorableListener {
|
|
2
|
+
groupName: string;
|
|
3
|
+
topic: string;
|
|
4
|
+
getStats(): {
|
|
5
|
+
listenerName: string;
|
|
6
|
+
topic: string;
|
|
7
|
+
groupName: string;
|
|
8
|
+
processed: number;
|
|
9
|
+
failed: number;
|
|
10
|
+
retries: number;
|
|
11
|
+
queueSize: number;
|
|
12
|
+
activeProcessing: number;
|
|
13
|
+
circuitBreakerOpen: boolean;
|
|
14
|
+
averageProcessingTime: number;
|
|
15
|
+
lastProcessedAt: Date;
|
|
16
|
+
config: any;
|
|
17
|
+
};
|
|
18
|
+
updateBacklogConfig(newConfig: any): void;
|
|
19
|
+
resetStats(): void;
|
|
20
|
+
forceCircuitBreaker(open: boolean): void;
|
|
21
|
+
}
|
|
22
|
+
export interface ListenerStats {
|
|
23
|
+
listenerName: string;
|
|
24
|
+
topic: string;
|
|
25
|
+
groupName: string;
|
|
26
|
+
processed: number;
|
|
27
|
+
failed: number;
|
|
28
|
+
retries: number;
|
|
29
|
+
queueSize: number;
|
|
30
|
+
activeProcessing: number;
|
|
31
|
+
circuitBreakerOpen: boolean;
|
|
32
|
+
averageProcessingTime: number;
|
|
33
|
+
successRate: number;
|
|
34
|
+
lastProcessedAt: Date;
|
|
35
|
+
config: any;
|
|
36
|
+
}
|
|
37
|
+
export interface SystemStats {
|
|
38
|
+
totalListeners: number;
|
|
39
|
+
activeListeners: number;
|
|
40
|
+
totalProcessed: number;
|
|
41
|
+
totalFailed: number;
|
|
42
|
+
totalRetries: number;
|
|
43
|
+
totalQueueSize: number;
|
|
44
|
+
totalActiveProcessing: number;
|
|
45
|
+
circuitBreakersOpen: number;
|
|
46
|
+
overallSuccessRate: number;
|
|
47
|
+
systemHealth: 'healthy' | 'degraded' | 'critical';
|
|
48
|
+
}
|
|
49
|
+
export declare class BacklogMonitor {
|
|
50
|
+
private static instance;
|
|
51
|
+
private listeners;
|
|
52
|
+
private constructor();
|
|
53
|
+
static getInstance(): BacklogMonitor;
|
|
54
|
+
/**
|
|
55
|
+
* Registra un listener para monitoreo (EnhancedListener o BatchEnhancedListener)
|
|
56
|
+
*/
|
|
57
|
+
registerListener(listener: MonitorableListener): void;
|
|
58
|
+
/**
|
|
59
|
+
* Desregistra un listener
|
|
60
|
+
*/
|
|
61
|
+
unregisterListener(groupName: string, topic: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Obtiene estadísticas de un listener específico
|
|
64
|
+
*/
|
|
65
|
+
getListenerStats(groupName: string, topic: string): ListenerStats | null;
|
|
66
|
+
/**
|
|
67
|
+
* Obtiene estadísticas de todos los listeners
|
|
68
|
+
*/
|
|
69
|
+
getAllListenersStats(): ListenerStats[];
|
|
70
|
+
/**
|
|
71
|
+
* Obtiene estadísticas del sistema completo
|
|
72
|
+
*/
|
|
73
|
+
getSystemStats(): SystemStats;
|
|
74
|
+
/**
|
|
75
|
+
* Actualiza configuración de un listener específico
|
|
76
|
+
*/
|
|
77
|
+
updateListenerConfig(groupName: string, topic: string, newConfig: any): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Actualiza configuración de todos los listeners
|
|
80
|
+
*/
|
|
81
|
+
updateAllListenersConfig(newConfig: any): number;
|
|
82
|
+
/**
|
|
83
|
+
* Resetea estadísticas de un listener específico
|
|
84
|
+
*/
|
|
85
|
+
resetListenerStats(groupName: string, topic: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Resetea estadísticas de todos los listeners
|
|
88
|
+
*/
|
|
89
|
+
resetAllStats(): number;
|
|
90
|
+
/**
|
|
91
|
+
* Fuerza circuit breaker para un listener específico
|
|
92
|
+
*/
|
|
93
|
+
forceCircuitBreaker(groupName: string, topic: string, open: boolean): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Obtiene resumen de salud del sistema
|
|
96
|
+
*/
|
|
97
|
+
getHealthSummary(): {
|
|
98
|
+
status: string;
|
|
99
|
+
message: string;
|
|
100
|
+
details: any;
|
|
101
|
+
};
|
|
102
|
+
}
|