jerkjs 2.5.8 → 2.6.1
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/CHANGELOG.md +162 -99
- package/README.md +113 -190
- package/RESULTADOS_WAF.md +63 -0
- package/doc-2.5/MANUAL_MODULOS_ADMIN.md +287 -0
- package/doc-2.5/QUEUE_CLI_MODULE_MANUAL.md +289 -0
- package/doc-2.5/QUEUE_SYSTEM_MANUAL.md +320 -0
- package/doc-2.5/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
- package/doc-2.5/WAF_MODULE_MANUAL.md +229 -0
- package/index.js +12 -3
- package/jerk-admin-client/README.md +69 -0
- package/jerk-admin-client/package.json +23 -0
- package/jerk-admin-client.js +257 -0
- package/lib/admin/AdminExtension.js +74 -19
- package/lib/admin/modules/ControllerGeneratorModule.js +414 -0
- package/lib/admin/modules/QueueManagementModule.js +265 -0
- package/lib/admin/modules/RouteCacheModule.js +227 -0
- package/lib/admin/modules/RouteManagerModule.js +468 -0
- package/lib/admin/modules/STATS_MODULE_README.md +15 -0
- package/lib/admin/modules/ViewCacheStatsModule.js +92 -0
- package/lib/admin/modules/WAFModule.js +737 -0
- package/lib/core/server.js +72 -69
- package/lib/middleware/firewall.js +112 -17
- package/lib/mvc/viewEngine.js +69 -10
- package/lib/queue/GlobalQueueStorage.js +38 -0
- package/lib/queue/QueueSystem.js +451 -0
- package/lib/queue/admin_example.js +114 -0
- package/lib/queue/example.js +268 -0
- package/lib/queue/integration.js +109 -0
- package/lib/utils/globalViewCacheInfo.js +16 -0
- package/lib/utils/globalWAFStats.js +54 -0
- package/package.json +2 -2
- package/test-colors.js +46 -0
- package/test-help-alias.js +31 -0
- package/ESTADISTICAS_RENDIMIENTO.md +0 -106
- package/debug_hook.js +0 -11
- package/docs/CACHE_SYSTEM_MAP.md +0 -206
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Almacenamiento Global de Colas para el Framework JERK
|
|
3
|
+
* Implementación del componente queue/GlobalQueueStorage.js
|
|
4
|
+
* Sistema de almacenamiento compartido globalmente para las colas
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Crear espacio de almacenamiento global para las colas si no existe
|
|
8
|
+
if (!global.jerkQueues) {
|
|
9
|
+
global.jerkQueues = new Map();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (!global.jerkQueueSystems) {
|
|
13
|
+
global.jerkQueueSystems = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!global.jerkQueueSystem) {
|
|
17
|
+
// Importar dinámicamente para evitar dependencias circulares
|
|
18
|
+
const QueueSystem = require('./QueueSystem');
|
|
19
|
+
const HookSystem = require('../core/hooks');
|
|
20
|
+
|
|
21
|
+
// Obtener hooks globales del framework si están disponibles
|
|
22
|
+
let globalHooks = null;
|
|
23
|
+
try {
|
|
24
|
+
const framework = require('../../index.js');
|
|
25
|
+
globalHooks = framework.hooks;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Si no están disponibles, crear instancia local
|
|
28
|
+
globalHooks = new HookSystem();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
global.jerkQueueSystem = new QueueSystem({ hooks: globalHooks });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
queues: global.jerkQueues,
|
|
36
|
+
queueSystems: global.jerkQueueSystems,
|
|
37
|
+
queueSystem: global.jerkQueueSystem
|
|
38
|
+
};
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sistema de Colas para el framework JERK
|
|
3
|
+
* Implementación del componente queue/QueueSystem.js
|
|
4
|
+
* Sistema de colas con soporte para N colas, hooks personalizados y manejo de fallback
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class QueueSystem {
|
|
8
|
+
/**
|
|
9
|
+
* Constructor del sistema de colas
|
|
10
|
+
* @param {Object} options - Opciones de configuración
|
|
11
|
+
*/
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
// Almacenar las colas
|
|
14
|
+
this.queues = new Map();
|
|
15
|
+
|
|
16
|
+
// Almacenar tareas pendientes por cola
|
|
17
|
+
this.pendingTasks = new Map();
|
|
18
|
+
|
|
19
|
+
// Almacenar tareas en proceso por cola
|
|
20
|
+
this.runningTasks = new Map();
|
|
21
|
+
|
|
22
|
+
// Almacenar tareas fallidas por cola
|
|
23
|
+
this.failedTasks = new Map();
|
|
24
|
+
|
|
25
|
+
// Almacenar hooks del sistema
|
|
26
|
+
this.globalHooks = options.hooks || null;
|
|
27
|
+
|
|
28
|
+
// Configuración por defecto
|
|
29
|
+
this.defaultConcurrency = options.concurrency || 1;
|
|
30
|
+
this.defaultRetryAttempts = options.retryAttempts || 3;
|
|
31
|
+
this.defaultRetryDelay = options.retryDelay || 1000; // milisegundos
|
|
32
|
+
|
|
33
|
+
// Estado del sistema
|
|
34
|
+
this.isRunning = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Obtiene o crea una cola específica
|
|
39
|
+
* @param {string} queueName - Nombre de la cola
|
|
40
|
+
* @param {Object} options - Opciones específicas para la cola
|
|
41
|
+
* @returns {Object} - Objeto de la cola
|
|
42
|
+
*/
|
|
43
|
+
getOrCreateQueue(queueName, options = {}) {
|
|
44
|
+
if (!this.queues.has(queueName)) {
|
|
45
|
+
const queue = {
|
|
46
|
+
name: queueName,
|
|
47
|
+
concurrency: options.concurrency || this.defaultConcurrency,
|
|
48
|
+
retryAttempts: options.retryAttempts || this.defaultRetryAttempts,
|
|
49
|
+
retryDelay: options.retryDelay || this.defaultRetryDelay,
|
|
50
|
+
tasks: [],
|
|
51
|
+
processing: false,
|
|
52
|
+
workers: 0,
|
|
53
|
+
maxWorkers: options.concurrency || this.defaultConcurrency,
|
|
54
|
+
hooks: options.hooks || null // Hooks específicos para esta cola
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
this.queues.set(queueName, queue);
|
|
58
|
+
|
|
59
|
+
// Inicializar estructuras de datos para esta cola
|
|
60
|
+
this.pendingTasks.set(queueName, []);
|
|
61
|
+
this.runningTasks.set(queueName, new Set());
|
|
62
|
+
this.failedTasks.set(queueName, []);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return this.queues.get(queueName);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Agrega una tarea a una cola
|
|
70
|
+
* @param {string} queueName - Nombre de la cola
|
|
71
|
+
* @param {Function} task - Función que representa la tarea
|
|
72
|
+
* @param {Object} data - Datos para la tarea
|
|
73
|
+
* @param {number} priority - Prioridad de la tarea (menor número = mayor prioridad)
|
|
74
|
+
* @returns {string} - ID único de la tarea
|
|
75
|
+
*/
|
|
76
|
+
addTask(queueName, task, data = {}, priority = 0) {
|
|
77
|
+
const taskId = this.generateTaskId();
|
|
78
|
+
|
|
79
|
+
const queue = this.getOrCreateQueue(queueName);
|
|
80
|
+
|
|
81
|
+
const taskObj = {
|
|
82
|
+
id: taskId,
|
|
83
|
+
task: task,
|
|
84
|
+
data: data,
|
|
85
|
+
priority: priority,
|
|
86
|
+
createdAt: Date.now(),
|
|
87
|
+
attempts: 0,
|
|
88
|
+
maxAttempts: queue.retryAttempts
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Agregar a la cola de tareas pendientes
|
|
92
|
+
const pendingQueue = this.pendingTasks.get(queueName);
|
|
93
|
+
pendingQueue.push(taskObj);
|
|
94
|
+
|
|
95
|
+
// Mantener la cola ordenada por prioridad
|
|
96
|
+
pendingQueue.sort((a, b) => a.priority - b.priority);
|
|
97
|
+
|
|
98
|
+
// Disparar hook cuando se agrega una tarea (primero global, luego específico de cola)
|
|
99
|
+
if (this.globalHooks) {
|
|
100
|
+
this.globalHooks.doAction('queue_task_added', queueName, taskObj);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Disparar hook específico de la cola
|
|
104
|
+
if (queue.hooks) {
|
|
105
|
+
queue.hooks.doAction('queue_task_added', queueName, taskObj);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Si el sistema está corriendo, intentar procesar la tarea
|
|
109
|
+
if (this.isRunning) {
|
|
110
|
+
setImmediate(() => {
|
|
111
|
+
this.processQueue(queueName);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return taskId;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Genera un ID único para una tarea
|
|
120
|
+
* @returns {string} - ID único de la tarea
|
|
121
|
+
*/
|
|
122
|
+
generateTaskId() {
|
|
123
|
+
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Inicia la ejecución de tareas en todas las colas
|
|
128
|
+
*/
|
|
129
|
+
start() {
|
|
130
|
+
if (this.isRunning) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.isRunning = true;
|
|
135
|
+
|
|
136
|
+
// Disparar hook cuando se inicia el sistema de colas (global)
|
|
137
|
+
if (this.globalHooks) {
|
|
138
|
+
this.globalHooks.doAction('queue_system_started');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Iniciar procesamiento para cada cola
|
|
142
|
+
for (const [queueName, queue] of this.queues.entries()) {
|
|
143
|
+
// Disparar hook cuando se inicia el sistema de colas (específico de cola)
|
|
144
|
+
if (queue.hooks) {
|
|
145
|
+
queue.hooks.doAction('queue_system_started', queueName);
|
|
146
|
+
}
|
|
147
|
+
this.processQueue(queueName);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Detiene la ejecución de tareas en todas las colas
|
|
153
|
+
*/
|
|
154
|
+
stop() {
|
|
155
|
+
this.isRunning = false;
|
|
156
|
+
|
|
157
|
+
// Disparar hook cuando se detiene el sistema de colas (global)
|
|
158
|
+
if (this.globalHooks) {
|
|
159
|
+
this.globalHooks.doAction('queue_system_stopped');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Disparar hook cuando se detiene el sistema de colas (específico de cada cola)
|
|
163
|
+
for (const [queueName, queue] of this.queues) {
|
|
164
|
+
if (queue.hooks) {
|
|
165
|
+
queue.hooks.doAction('queue_system_stopped', queueName);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Procesa tareas en una cola específica
|
|
172
|
+
* @param {string} queueName - Nombre de la cola
|
|
173
|
+
*/
|
|
174
|
+
async processQueue(queueName) {
|
|
175
|
+
if (!this.isRunning) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const queue = this.queues.get(queueName);
|
|
180
|
+
if (!queue || queue.processing || queue.paused) {
|
|
181
|
+
// Ya se está procesando esta cola o está pausada, salir para evitar condiciones de carrera
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Marcar la cola como en proceso para evitar condiciones de carrera
|
|
186
|
+
queue.processing = true;
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
// Procesar tareas mientras haya tareas pendientes y capacidad de trabajo
|
|
190
|
+
while (
|
|
191
|
+
this.isRunning &&
|
|
192
|
+
!queue.paused && // Asegurarse de que la cola no esté pausada
|
|
193
|
+
queue.workers < queue.maxWorkers &&
|
|
194
|
+
this.pendingTasks.get(queueName).length > 0
|
|
195
|
+
) {
|
|
196
|
+
const task = this.pendingTasks.get(queueName).shift();
|
|
197
|
+
|
|
198
|
+
if (task) {
|
|
199
|
+
// Marcar la tarea como en proceso
|
|
200
|
+
this.runningTasks.get(queueName).add(task.id);
|
|
201
|
+
|
|
202
|
+
// Incrementar contador de workers
|
|
203
|
+
queue.workers++;
|
|
204
|
+
|
|
205
|
+
// Procesar la tarea en segundo plano
|
|
206
|
+
this.executeTask(queueName, task).finally(() => {
|
|
207
|
+
// Decrementar contador de workers
|
|
208
|
+
queue.workers--;
|
|
209
|
+
|
|
210
|
+
// Remover la tarea de las tareas en proceso
|
|
211
|
+
this.runningTasks.get(queueName).delete(task.id);
|
|
212
|
+
|
|
213
|
+
// Continuar procesando si el sistema sigue corriendo
|
|
214
|
+
if (this.isRunning && !queue.paused) {
|
|
215
|
+
setImmediate(() => {
|
|
216
|
+
this.processQueue(queueName);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} finally {
|
|
223
|
+
// Marcar la cola como no en proceso
|
|
224
|
+
queue.processing = false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Ejecuta una tarea específica
|
|
230
|
+
* @param {string} queueName - Nombre de la cola
|
|
231
|
+
* @param {Object} task - Objeto de la tarea
|
|
232
|
+
*/
|
|
233
|
+
async executeTask(queueName, task) {
|
|
234
|
+
const queue = this.queues.get(queueName);
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
// Disparar hook antes de ejecutar la tarea (primero global, luego específico de cola)
|
|
238
|
+
let processedTask = task.task;
|
|
239
|
+
|
|
240
|
+
// Aplicar filtro global si existe
|
|
241
|
+
if (this.globalHooks) {
|
|
242
|
+
processedTask = this.globalHooks.applyFilters('queue_execute_task', processedTask, queueName, task);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Aplicar filtro específico de la cola si existe
|
|
246
|
+
if (queue.hooks) {
|
|
247
|
+
processedTask = queue.hooks.applyFilters('queue_execute_task', processedTask, queueName, task);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
await processedTask(task.data, task);
|
|
251
|
+
|
|
252
|
+
// Disparar hook cuando la tarea se completa exitosamente (global y específico)
|
|
253
|
+
if (this.globalHooks) {
|
|
254
|
+
this.globalHooks.doAction('queue_task_completed', queueName, task);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (queue.hooks) {
|
|
258
|
+
queue.hooks.doAction('queue_task_completed', queueName, task);
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
// Incrementar intentos
|
|
262
|
+
task.attempts++;
|
|
263
|
+
|
|
264
|
+
// Disparar hook cuando la tarea falla (global y específico)
|
|
265
|
+
if (this.globalHooks) {
|
|
266
|
+
this.globalHooks.doAction('queue_task_failed', queueName, task, error);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (queue.hooks) {
|
|
270
|
+
queue.hooks.doAction('queue_task_failed', queueName, task, error);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Verificar si hay más intentos disponibles
|
|
274
|
+
if (task.attempts < task.maxAttempts) {
|
|
275
|
+
// Agregar de nuevo a la cola con retraso
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
const pendingQueue = this.pendingTasks.get(queueName);
|
|
278
|
+
pendingQueue.push(task);
|
|
279
|
+
pendingQueue.sort((a, b) => a.priority - b.priority);
|
|
280
|
+
|
|
281
|
+
// Disparar hook cuando se reintenta una tarea (global y específico)
|
|
282
|
+
if (this.globalHooks) {
|
|
283
|
+
this.globalHooks.doAction('queue_task_retry', queueName, task);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (queue.hooks) {
|
|
287
|
+
queue.hooks.doAction('queue_task_retry', queueName, task);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (this.isRunning) {
|
|
291
|
+
this.processQueue(queueName);
|
|
292
|
+
}
|
|
293
|
+
}, this.queues.get(queueName).retryDelay);
|
|
294
|
+
} else {
|
|
295
|
+
// Agregar a la cola de tareas fallidas
|
|
296
|
+
const failedQueue = this.failedTasks.get(queueName);
|
|
297
|
+
failedQueue.push(task);
|
|
298
|
+
|
|
299
|
+
// Disparar hook de fallback para tareas que han fallado definitivamente (global y específico)
|
|
300
|
+
if (this.globalHooks) {
|
|
301
|
+
// Permitir que los hooks manejen la lógica de fallback
|
|
302
|
+
this.globalHooks.doAction('queue_task_fallback', queueName, task, error);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (queue.hooks) {
|
|
306
|
+
// Permitir que los hooks específicos de la cola manejen la lógica de fallback
|
|
307
|
+
queue.hooks.doAction('queue_task_fallback', queueName, task, error);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Obtiene el estado actual del sistema de colas
|
|
315
|
+
* @returns {Object} - Estado del sistema de colas
|
|
316
|
+
*/
|
|
317
|
+
getStatus() {
|
|
318
|
+
const status = {};
|
|
319
|
+
|
|
320
|
+
for (const [queueName, queue] of this.queues.entries()) {
|
|
321
|
+
status[queueName] = {
|
|
322
|
+
name: queueName,
|
|
323
|
+
pendingTasks: this.pendingTasks.get(queueName).length,
|
|
324
|
+
runningTasks: this.runningTasks.get(queueName).size,
|
|
325
|
+
failedTasks: this.failedTasks.get(queueName).length,
|
|
326
|
+
workers: queue.workers,
|
|
327
|
+
maxWorkers: queue.maxWorkers,
|
|
328
|
+
processing: queue.processing,
|
|
329
|
+
paused: queue.paused || false
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return status;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Pausa una cola específica
|
|
338
|
+
* @param {string} queueName - Nombre de la cola a pausar
|
|
339
|
+
* @returns {boolean} - True si la cola fue pausada exitosamente
|
|
340
|
+
*/
|
|
341
|
+
pauseQueue(queueName) {
|
|
342
|
+
const queue = this.queues.get(queueName);
|
|
343
|
+
if (!queue) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
queue.paused = true;
|
|
348
|
+
|
|
349
|
+
// Disparar hook cuando se pausa una cola
|
|
350
|
+
if (this.globalHooks) {
|
|
351
|
+
this.globalHooks.doAction('queue_paused', queueName);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Reanuda una cola específica
|
|
359
|
+
* @param {string} queueName - Nombre de la cola a reanudar
|
|
360
|
+
* @returns {boolean} - True si la cola fue reanudada exitosamente
|
|
361
|
+
*/
|
|
362
|
+
resumeQueue(queueName) {
|
|
363
|
+
const queue = this.queues.get(queueName);
|
|
364
|
+
if (!queue) {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
queue.paused = false;
|
|
369
|
+
|
|
370
|
+
// Disparar hook cuando se reanuda una cola
|
|
371
|
+
if (this.globalHooks) {
|
|
372
|
+
this.globalHooks.doAction('queue_resumed', queueName);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Si el sistema está corriendo, iniciar procesamiento
|
|
376
|
+
if (this.isRunning) {
|
|
377
|
+
setImmediate(() => {
|
|
378
|
+
this.processQueue(queueName);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Limpia las tareas pendientes de una cola específica
|
|
387
|
+
* @param {string} queueName - Nombre de la cola a limpiar
|
|
388
|
+
* @returns {boolean} - True si la cola fue limpiada exitosamente
|
|
389
|
+
*/
|
|
390
|
+
clearQueue(queueName) {
|
|
391
|
+
const queue = this.queues.get(queueName);
|
|
392
|
+
if (!queue) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Limpiar tareas pendientes
|
|
397
|
+
const pendingQueue = this.pendingTasks.get(queueName);
|
|
398
|
+
if (pendingQueue) {
|
|
399
|
+
pendingQueue.length = 0;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Disparar hook cuando se limpia una cola
|
|
403
|
+
if (this.globalHooks) {
|
|
404
|
+
this.globalHooks.doAction('queue_cleared', queueName);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Limpia las tareas fallidas de una cola específica
|
|
412
|
+
* @param {string} queueName - Nombre de la cola
|
|
413
|
+
*/
|
|
414
|
+
clearFailedTasks(queueName) {
|
|
415
|
+
if (this.failedTasks.has(queueName)) {
|
|
416
|
+
this.failedTasks.get(queueName).length = 0;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Reintenta todas las tareas fallidas en una cola específica
|
|
422
|
+
* @param {string} queueName - Nombre de la cola
|
|
423
|
+
*/
|
|
424
|
+
retryFailedTasks(queueName) {
|
|
425
|
+
if (!this.failedTasks.has(queueName)) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const failedQueue = this.failedTasks.get(queueName);
|
|
430
|
+
const pendingQueue = this.pendingTasks.get(queueName);
|
|
431
|
+
|
|
432
|
+
// Resetear intentos para todas las tareas fallidas
|
|
433
|
+
for (const task of failedQueue) {
|
|
434
|
+
task.attempts = 0;
|
|
435
|
+
pendingQueue.push(task);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Vaciar la cola de tareas fallidas
|
|
439
|
+
failedQueue.length = 0;
|
|
440
|
+
|
|
441
|
+
// Reordenar la cola de pendientes
|
|
442
|
+
pendingQueue.sort((a, b) => a.priority - b.priority);
|
|
443
|
+
|
|
444
|
+
// Procesar la cola si el sistema está corriendo
|
|
445
|
+
if (this.isRunning) {
|
|
446
|
+
this.processQueue(queueName);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
module.exports = QueueSystem;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de uso del sistema de colas con módulo de administración
|
|
3
|
+
* Archivo de ejemplo: queue/admin_example.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { APIServer, QueueIntegration } = require('../../index.js');
|
|
7
|
+
|
|
8
|
+
// Crear servidor
|
|
9
|
+
const server = new APIServer({ port: 3000 });
|
|
10
|
+
|
|
11
|
+
// Crear instancia de la integración de colas
|
|
12
|
+
const queueIntegration = new QueueIntegration();
|
|
13
|
+
const queueSystem = queueIntegration.getQueueSystem();
|
|
14
|
+
|
|
15
|
+
// Ejemplo de tarea simple
|
|
16
|
+
function ejemploTarea(datos, taskObj) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
console.log(`Procesando tarea con datos:`, datos);
|
|
19
|
+
|
|
20
|
+
// Simular un proceso que podría fallar
|
|
21
|
+
if (Math.random() < 0.3) { // 30% de probabilidad de fallo
|
|
22
|
+
console.error(`Falló la tarea con ID: ${taskObj.id}`);
|
|
23
|
+
reject(new Error(`Tarea fallida intencionalmente`));
|
|
24
|
+
} else {
|
|
25
|
+
console.log(`Tarea completada exitosamente con ID: ${taskObj.id}`);
|
|
26
|
+
resolve(`Resultado de la tarea con ID: ${taskObj.id}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Simular tiempo de procesamiento
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
if (Math.random() < 0.3) {
|
|
32
|
+
reject(new Error(`Tarea fallida después de procesamiento`));
|
|
33
|
+
} else {
|
|
34
|
+
resolve(`Tarea completada con éxito`);
|
|
35
|
+
}
|
|
36
|
+
}, 1000);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Crear algunas colas de ejemplo
|
|
41
|
+
queueIntegration.createQueue('imagenes', {
|
|
42
|
+
concurrency: 3,
|
|
43
|
+
retryAttempts: 2,
|
|
44
|
+
retryDelay: 1000
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
queueIntegration.createQueue('correos', {
|
|
48
|
+
concurrency: 2,
|
|
49
|
+
retryAttempts: 3,
|
|
50
|
+
retryDelay: 2000
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
queueIntegration.createQueue('pagos', {
|
|
54
|
+
concurrency: 1,
|
|
55
|
+
retryAttempts: 5,
|
|
56
|
+
retryDelay: 3000
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Agregar algunas tareas a las colas
|
|
60
|
+
console.log("Agregando tareas a las colas...");
|
|
61
|
+
|
|
62
|
+
// Tareas para cola de imágenes
|
|
63
|
+
for (let i = 0; i < 3; i++) {
|
|
64
|
+
queueIntegration.addTask('imagenes', ejemploTarea, {
|
|
65
|
+
id: i,
|
|
66
|
+
tipo: 'imagen',
|
|
67
|
+
nombre: `imagen_${i}.jpg`
|
|
68
|
+
}, i);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Tareas para cola de correos
|
|
72
|
+
for (let i = 0; i < 3; i++) {
|
|
73
|
+
queueIntegration.addTask('correos', ejemploTarea, {
|
|
74
|
+
id: i,
|
|
75
|
+
tipo: 'correo',
|
|
76
|
+
destinatario: `usuario${i}@ejemplo.com`
|
|
77
|
+
}, i);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Tareas para cola de pagos
|
|
81
|
+
for (let i = 0; i < 3; i++) {
|
|
82
|
+
queueIntegration.addTask('pagos', ejemploTarea, {
|
|
83
|
+
id: i,
|
|
84
|
+
tipo: 'pago',
|
|
85
|
+
monto: 100 + i * 50
|
|
86
|
+
}, i);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Iniciar el sistema de colas
|
|
90
|
+
console.log("Iniciando el sistema de colas...");
|
|
91
|
+
queueIntegration.start();
|
|
92
|
+
|
|
93
|
+
// Iniciar el servidor y la extensión de administración
|
|
94
|
+
server.start();
|
|
95
|
+
|
|
96
|
+
// Inicializar la extensión de administración en el puerto 9999
|
|
97
|
+
server.initializeAdminExtension({
|
|
98
|
+
port: 9999,
|
|
99
|
+
host: '127.0.0.1'
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
console.log("Servidor iniciado en http://localhost:3000");
|
|
103
|
+
console.log("Extensión de administración disponible en telnet localhost 9999");
|
|
104
|
+
console.log("Comandos disponibles para colas: queues, queue-info, queue-pause, queue-resume, queue-clear, queue-retry-failed");
|
|
105
|
+
|
|
106
|
+
// Mostrar estado periódicamente
|
|
107
|
+
setInterval(() => {
|
|
108
|
+
console.log('\n--- Estado del sistema de colas ---');
|
|
109
|
+
const status = queueIntegration.getStatus();
|
|
110
|
+
for (const [queueName, queueStatus] of Object.entries(status)) {
|
|
111
|
+
console.log(`${queueName}: Pendientes=${queueStatus.pendingTasks}, En proceso=${queueStatus.runningTasks}, Fallidas=${queueStatus.failedTasks}, Pausada=${queueStatus.paused}`);
|
|
112
|
+
}
|
|
113
|
+
console.log('------------------------------------\n');
|
|
114
|
+
}, 10000);
|