atomic-queues 1.0.13

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.
Files changed (110) hide show
  1. package/README.md +686 -0
  2. package/dist/decorators/decorators.d.ts +67 -0
  3. package/dist/decorators/decorators.d.ts.map +1 -0
  4. package/dist/decorators/decorators.js +91 -0
  5. package/dist/decorators/decorators.js.map +1 -0
  6. package/dist/decorators/index.d.ts +2 -0
  7. package/dist/decorators/index.d.ts.map +1 -0
  8. package/dist/decorators/index.js +18 -0
  9. package/dist/decorators/index.js.map +1 -0
  10. package/dist/domain/index.d.ts +5 -0
  11. package/dist/domain/index.d.ts.map +1 -0
  12. package/dist/domain/index.js +21 -0
  13. package/dist/domain/index.js.map +1 -0
  14. package/dist/domain/interfaces.d.ts +614 -0
  15. package/dist/domain/interfaces.d.ts.map +1 -0
  16. package/dist/domain/interfaces.js +19 -0
  17. package/dist/domain/interfaces.js.map +1 -0
  18. package/dist/index.d.ts +40 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +61 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/module/atomic-queues.module.d.ts +97 -0
  23. package/dist/module/atomic-queues.module.d.ts.map +1 -0
  24. package/dist/module/atomic-queues.module.js +197 -0
  25. package/dist/module/atomic-queues.module.js.map +1 -0
  26. package/dist/module/index.d.ts +2 -0
  27. package/dist/module/index.d.ts.map +1 -0
  28. package/dist/module/index.js +18 -0
  29. package/dist/module/index.js.map +1 -0
  30. package/dist/services/constants.d.ts +10 -0
  31. package/dist/services/constants.d.ts.map +1 -0
  32. package/dist/services/constants.js +13 -0
  33. package/dist/services/constants.js.map +1 -0
  34. package/dist/services/cron-manager/cron-manager.service.d.ts +188 -0
  35. package/dist/services/cron-manager/cron-manager.service.d.ts.map +1 -0
  36. package/dist/services/cron-manager/cron-manager.service.js +534 -0
  37. package/dist/services/cron-manager/cron-manager.service.js.map +1 -0
  38. package/dist/services/cron-manager/index.d.ts +2 -0
  39. package/dist/services/cron-manager/index.d.ts.map +1 -0
  40. package/dist/services/cron-manager/index.js +18 -0
  41. package/dist/services/cron-manager/index.js.map +1 -0
  42. package/dist/services/index-manager/index-manager.service.d.ts +146 -0
  43. package/dist/services/index-manager/index-manager.service.d.ts.map +1 -0
  44. package/dist/services/index-manager/index-manager.service.js +337 -0
  45. package/dist/services/index-manager/index-manager.service.js.map +1 -0
  46. package/dist/services/index-manager/index.d.ts +2 -0
  47. package/dist/services/index-manager/index.d.ts.map +1 -0
  48. package/dist/services/index-manager/index.js +18 -0
  49. package/dist/services/index-manager/index.js.map +1 -0
  50. package/dist/services/index.d.ts +10 -0
  51. package/dist/services/index.d.ts.map +1 -0
  52. package/dist/services/index.js +26 -0
  53. package/dist/services/index.js.map +1 -0
  54. package/dist/services/job-processor/index.d.ts +2 -0
  55. package/dist/services/job-processor/index.d.ts.map +1 -0
  56. package/dist/services/job-processor/index.js +18 -0
  57. package/dist/services/job-processor/index.js.map +1 -0
  58. package/dist/services/job-processor/job-processor.service.d.ts +156 -0
  59. package/dist/services/job-processor/job-processor.service.d.ts.map +1 -0
  60. package/dist/services/job-processor/job-processor.service.js +331 -0
  61. package/dist/services/job-processor/job-processor.service.js.map +1 -0
  62. package/dist/services/queue-manager/index.d.ts +2 -0
  63. package/dist/services/queue-manager/index.d.ts.map +1 -0
  64. package/dist/services/queue-manager/index.js +18 -0
  65. package/dist/services/queue-manager/index.js.map +1 -0
  66. package/dist/services/queue-manager/queue-manager.service.d.ts +128 -0
  67. package/dist/services/queue-manager/queue-manager.service.d.ts.map +1 -0
  68. package/dist/services/queue-manager/queue-manager.service.js +308 -0
  69. package/dist/services/queue-manager/queue-manager.service.js.map +1 -0
  70. package/dist/services/resource-lock/index.d.ts +2 -0
  71. package/dist/services/resource-lock/index.d.ts.map +1 -0
  72. package/dist/services/resource-lock/index.js +18 -0
  73. package/dist/services/resource-lock/index.js.map +1 -0
  74. package/dist/services/resource-lock/resource-lock.service.d.ts +124 -0
  75. package/dist/services/resource-lock/resource-lock.service.d.ts.map +1 -0
  76. package/dist/services/resource-lock/resource-lock.service.js +379 -0
  77. package/dist/services/resource-lock/resource-lock.service.js.map +1 -0
  78. package/dist/services/service-queue/index.d.ts +2 -0
  79. package/dist/services/service-queue/index.d.ts.map +1 -0
  80. package/dist/services/service-queue/index.js +18 -0
  81. package/dist/services/service-queue/index.js.map +1 -0
  82. package/dist/services/service-queue/service-queue.service.d.ts +232 -0
  83. package/dist/services/service-queue/service-queue.service.d.ts.map +1 -0
  84. package/dist/services/service-queue/service-queue.service.js +647 -0
  85. package/dist/services/service-queue/service-queue.service.js.map +1 -0
  86. package/dist/services/shutdown-state/index.d.ts +2 -0
  87. package/dist/services/shutdown-state/index.d.ts.map +1 -0
  88. package/dist/services/shutdown-state/index.js +18 -0
  89. package/dist/services/shutdown-state/index.js.map +1 -0
  90. package/dist/services/shutdown-state/shutdown-state.service.d.ts +69 -0
  91. package/dist/services/shutdown-state/shutdown-state.service.d.ts.map +1 -0
  92. package/dist/services/shutdown-state/shutdown-state.service.js +127 -0
  93. package/dist/services/shutdown-state/shutdown-state.service.js.map +1 -0
  94. package/dist/services/worker-manager/index.d.ts +2 -0
  95. package/dist/services/worker-manager/index.d.ts.map +1 -0
  96. package/dist/services/worker-manager/index.js +18 -0
  97. package/dist/services/worker-manager/index.js.map +1 -0
  98. package/dist/services/worker-manager/worker-manager.service.d.ts +163 -0
  99. package/dist/services/worker-manager/worker-manager.service.d.ts.map +1 -0
  100. package/dist/services/worker-manager/worker-manager.service.js +460 -0
  101. package/dist/services/worker-manager/worker-manager.service.js.map +1 -0
  102. package/dist/utils/helpers.d.ts +124 -0
  103. package/dist/utils/helpers.d.ts.map +1 -0
  104. package/dist/utils/helpers.js +229 -0
  105. package/dist/utils/helpers.js.map +1 -0
  106. package/dist/utils/index.d.ts +2 -0
  107. package/dist/utils/index.d.ts.map +1 -0
  108. package/dist/utils/index.js +18 -0
  109. package/dist/utils/index.js.map +1 -0
  110. package/package.json +80 -0
@@ -0,0 +1,379 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ var ResourceLockService_1;
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.ResourceLockService = void 0;
20
+ const common_1 = require("@nestjs/common");
21
+ const ioredis_1 = __importDefault(require("ioredis"));
22
+ const constants_1 = require("../constants");
23
+ /**
24
+ * ResourceLockService
25
+ *
26
+ * Provides distributed resource locking using Redis.
27
+ * Implements patterns from both Whatsapi (context locking) and bl-blackjack-service.
28
+ *
29
+ * Key Features:
30
+ * - Atomic lock acquisition using Lua scripts
31
+ * - TTL-based lock expiration
32
+ * - Lock ownership verification
33
+ * - Pool-based resource allocation (get first available from pool)
34
+ * - Lock extension for long-running operations
35
+ *
36
+ * Use Cases:
37
+ * - Whatsapi: Lock WhatsApp contexts for message sending
38
+ * - Blackjack: Lock table resources for game operations
39
+ * - General: Any resource that needs exclusive access
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // Acquire a lock on a context
44
+ * const result = await lockService.acquireLock(
45
+ * 'context',
46
+ * 'context-123',
47
+ * 'user-456',
48
+ * 'user',
49
+ * 60, // 60 second TTL
50
+ * );
51
+ *
52
+ * if (result.acquired) {
53
+ * // Do work with the context
54
+ * await lockService.releaseLock('context', 'context-123');
55
+ * }
56
+ *
57
+ * // Get first available context from a pool
58
+ * const available = await lockService.getAvailableResource(
59
+ * 'context',
60
+ * ['ctx-1', 'ctx-2', 'ctx-3'],
61
+ * 'user-456',
62
+ * 'user',
63
+ * );
64
+ * ```
65
+ */
66
+ let ResourceLockService = ResourceLockService_1 = class ResourceLockService {
67
+ constructor(redis, config) {
68
+ this.redis = redis;
69
+ this.config = config;
70
+ this.logger = new common_1.Logger(ResourceLockService_1.name);
71
+ // Lua script for atomic lock acquisition
72
+ this.ACQUIRE_LOCK_SCRIPT = `
73
+ local lockKey = KEYS[1]
74
+ local lockValue = ARGV[1]
75
+ local ttl = tonumber(ARGV[2])
76
+
77
+ local current = redis.call("GET", lockKey)
78
+
79
+ if not current then
80
+ redis.call("SET", lockKey, lockValue, "EX", ttl)
81
+ return 1 -- Lock acquired
82
+ else
83
+ return 0 -- Lock already held
84
+ end
85
+ `;
86
+ // Lua script for atomic lock release with ownership check
87
+ this.RELEASE_LOCK_SCRIPT = `
88
+ local lockKey = KEYS[1]
89
+ local expectedOwner = ARGV[1]
90
+
91
+ local current = redis.call("GET", lockKey)
92
+
93
+ if current then
94
+ local lockData = cjson.decode(current)
95
+ if lockData.ownerId == expectedOwner then
96
+ redis.call("DEL", lockKey)
97
+ return 1 -- Lock released
98
+ else
99
+ return 0 -- Not the owner
100
+ end
101
+ end
102
+
103
+ return 1 -- Lock didn't exist
104
+ `;
105
+ // Lua script for extending lock TTL
106
+ this.EXTEND_LOCK_SCRIPT = `
107
+ local lockKey = KEYS[1]
108
+ local newTtl = tonumber(ARGV[1])
109
+
110
+ local exists = redis.call("EXISTS", lockKey)
111
+
112
+ if exists == 1 then
113
+ redis.call("EXPIRE", lockKey, newTtl)
114
+ return 1 -- TTL extended
115
+ else
116
+ return 0 -- Lock doesn't exist
117
+ end
118
+ `;
119
+ this.keyPrefix = config.keyPrefix || 'aq';
120
+ }
121
+ /**
122
+ * Acquire a lock on a resource.
123
+ *
124
+ * Uses Lua script for atomic check-and-set operation.
125
+ * The lock includes ownership information for later verification.
126
+ */
127
+ async acquireLock(resourceType, resourceId, ownerId, ownerType, ttlSeconds = 60, metadata) {
128
+ const lockKey = this.getLockKey(resourceType, resourceId);
129
+ const now = new Date();
130
+ const lockData = {
131
+ resourceId,
132
+ resourceType,
133
+ ownerId,
134
+ ownerType,
135
+ acquiredAt: now,
136
+ expiresAt: new Date(now.getTime() + ttlSeconds * 1000),
137
+ metadata,
138
+ };
139
+ try {
140
+ const result = await this.redis.eval(this.ACQUIRE_LOCK_SCRIPT, 1, lockKey, JSON.stringify(lockData), ttlSeconds.toString());
141
+ if (result === 1) {
142
+ this.logger.debug(`Lock acquired: ${resourceType}/${resourceId} by ${ownerType}/${ownerId}`);
143
+ return { acquired: true, lock: lockData };
144
+ }
145
+ this.logger.debug(`Lock not acquired (already held): ${resourceType}/${resourceId}`);
146
+ return {
147
+ acquired: false,
148
+ reason: 'Resource is already locked',
149
+ };
150
+ }
151
+ catch (error) {
152
+ this.logger.error(`Error acquiring lock for ${resourceType}/${resourceId}:`, error);
153
+ return {
154
+ acquired: false,
155
+ reason: `Error: ${error.message}`,
156
+ };
157
+ }
158
+ }
159
+ /**
160
+ * Release a lock on a resource.
161
+ */
162
+ async releaseLock(resourceType, resourceId) {
163
+ const lockKey = this.getLockKey(resourceType, resourceId);
164
+ try {
165
+ await this.redis.del(lockKey);
166
+ this.logger.debug(`Lock released: ${resourceType}/${resourceId}`);
167
+ return true;
168
+ }
169
+ catch (error) {
170
+ this.logger.error(`Error releasing lock for ${resourceType}/${resourceId}:`, error);
171
+ return false;
172
+ }
173
+ }
174
+ /**
175
+ * Release a lock with ownership verification.
176
+ * Only releases if the current owner matches the expected owner.
177
+ */
178
+ async releaseOwnedLock(resourceType, resourceId, ownerId) {
179
+ const lockKey = this.getLockKey(resourceType, resourceId);
180
+ try {
181
+ const result = await this.redis.eval(this.RELEASE_LOCK_SCRIPT, 1, lockKey, ownerId);
182
+ const released = result === 1;
183
+ if (released) {
184
+ this.logger.debug(`Lock released by owner: ${resourceType}/${resourceId}`);
185
+ }
186
+ else {
187
+ this.logger.warn(`Lock release failed (not owner): ${resourceType}/${resourceId}`);
188
+ }
189
+ return released;
190
+ }
191
+ catch (error) {
192
+ this.logger.error(`Error releasing owned lock for ${resourceType}/${resourceId}:`, error);
193
+ return false;
194
+ }
195
+ }
196
+ /**
197
+ * Check if a resource is locked.
198
+ */
199
+ async isLocked(resourceType, resourceId) {
200
+ const lockKey = this.getLockKey(resourceType, resourceId);
201
+ const exists = await this.redis.exists(lockKey);
202
+ return exists === 1;
203
+ }
204
+ /**
205
+ * Get lock info for a resource.
206
+ */
207
+ async getLockInfo(resourceType, resourceId) {
208
+ const lockKey = this.getLockKey(resourceType, resourceId);
209
+ const data = await this.redis.get(lockKey);
210
+ if (!data)
211
+ return null;
212
+ try {
213
+ const lock = JSON.parse(data);
214
+ // Convert date strings back to Date objects
215
+ lock.acquiredAt = new Date(lock.acquiredAt);
216
+ lock.expiresAt = new Date(lock.expiresAt);
217
+ return lock;
218
+ }
219
+ catch (error) {
220
+ this.logger.error(`Error parsing lock data for ${lockKey}:`, error);
221
+ return null;
222
+ }
223
+ }
224
+ /**
225
+ * Get all locked resources of a type for an owner.
226
+ */
227
+ async getOwnerLocks(ownerType, ownerId) {
228
+ // Scan for all locks and filter by owner
229
+ const pattern = `${this.keyPrefix}:lock:*`;
230
+ const keys = await this.scanKeys(pattern);
231
+ const locks = [];
232
+ for (const key of keys) {
233
+ const data = await this.redis.get(key);
234
+ if (data) {
235
+ try {
236
+ const lock = JSON.parse(data);
237
+ if (lock.ownerType === ownerType && lock.ownerId === ownerId) {
238
+ lock.acquiredAt = new Date(lock.acquiredAt);
239
+ lock.expiresAt = new Date(lock.expiresAt);
240
+ locks.push(lock);
241
+ }
242
+ }
243
+ catch {
244
+ // Skip invalid entries
245
+ }
246
+ }
247
+ }
248
+ return locks;
249
+ }
250
+ /**
251
+ * Get an available (unlocked) resource from a pool of candidates.
252
+ * Shuffles the pool for fair distribution.
253
+ * Atomically locks and returns the first available resource.
254
+ *
255
+ * This is the pattern used by Whatsapi to find an available WhatsApp context.
256
+ */
257
+ async getAvailableResource(resourceType, candidateIds, ownerId, ownerType, ttlSeconds = 60) {
258
+ // Shuffle candidates for fair distribution
259
+ const shuffled = this.shuffleArray([...candidateIds]);
260
+ for (const resourceId of shuffled) {
261
+ const result = await this.acquireLock(resourceType, resourceId, ownerId, ownerType, ttlSeconds);
262
+ if (result.acquired) {
263
+ this.logger.debug(`Found available resource: ${resourceType}/${resourceId}`);
264
+ return result;
265
+ }
266
+ }
267
+ this.logger.debug(`No available resource found in pool for ${ownerType}/${ownerId}`);
268
+ return {
269
+ acquired: false,
270
+ reason: 'No available resources in pool',
271
+ };
272
+ }
273
+ /**
274
+ * Extend the TTL of an existing lock.
275
+ */
276
+ async extendLock(resourceType, resourceId, ttlSeconds) {
277
+ const lockKey = this.getLockKey(resourceType, resourceId);
278
+ try {
279
+ const result = await this.redis.eval(this.EXTEND_LOCK_SCRIPT, 1, lockKey, ttlSeconds.toString());
280
+ const extended = result === 1;
281
+ if (extended) {
282
+ this.logger.debug(`Lock TTL extended: ${resourceType}/${resourceId} to ${ttlSeconds}s`);
283
+ }
284
+ return extended;
285
+ }
286
+ catch (error) {
287
+ this.logger.error(`Error extending lock for ${resourceType}/${resourceId}:`, error);
288
+ return false;
289
+ }
290
+ }
291
+ /**
292
+ * Get all locks for a resource type.
293
+ */
294
+ async getResourceTypeLocks(resourceType) {
295
+ const pattern = `${this.keyPrefix}:lock:${resourceType}:*`;
296
+ const keys = await this.scanKeys(pattern);
297
+ const locked = [];
298
+ for (const key of keys) {
299
+ const data = await this.redis.get(key);
300
+ if (data) {
301
+ try {
302
+ const lock = JSON.parse(data);
303
+ lock.acquiredAt = new Date(lock.acquiredAt);
304
+ lock.expiresAt = new Date(lock.expiresAt);
305
+ locked.push(lock);
306
+ }
307
+ catch {
308
+ // Skip invalid entries
309
+ }
310
+ }
311
+ }
312
+ return {
313
+ locked,
314
+ free: [], // This would need external resource registry to determine
315
+ };
316
+ }
317
+ /**
318
+ * Cross-verify that a lock is still held by the expected owner.
319
+ * Useful for operations that need to verify lock ownership mid-operation.
320
+ */
321
+ async verifyLockOwnership(resourceType, resourceId, ownerId) {
322
+ const lock = await this.getLockInfo(resourceType, resourceId);
323
+ return lock !== null && lock.ownerId === ownerId;
324
+ }
325
+ /**
326
+ * Clear all locks for an owner (useful for cleanup).
327
+ */
328
+ async clearOwnerLocks(ownerType, ownerId) {
329
+ const locks = await this.getOwnerLocks(ownerType, ownerId);
330
+ let cleared = 0;
331
+ for (const lock of locks) {
332
+ const released = await this.releaseLock(lock.resourceType, lock.resourceId);
333
+ if (released)
334
+ cleared++;
335
+ }
336
+ this.logger.debug(`Cleared ${cleared} locks for ${ownerType}/${ownerId}`);
337
+ return cleared;
338
+ }
339
+ // =========================================================================
340
+ // PRIVATE METHODS
341
+ // =========================================================================
342
+ /**
343
+ * Get the Redis key for a lock.
344
+ */
345
+ getLockKey(resourceType, resourceId) {
346
+ return `${this.keyPrefix}:lock:${resourceType}:${resourceId}`;
347
+ }
348
+ /**
349
+ * Scan Redis keys matching a pattern.
350
+ */
351
+ async scanKeys(pattern) {
352
+ let cursor = '0';
353
+ const keys = [];
354
+ do {
355
+ const [nextCursor, scanKeys] = await this.redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
356
+ cursor = nextCursor;
357
+ keys.push(...scanKeys);
358
+ } while (cursor !== '0');
359
+ return keys;
360
+ }
361
+ /**
362
+ * Fisher-Yates shuffle algorithm.
363
+ */
364
+ shuffleArray(array) {
365
+ for (let i = array.length - 1; i > 0; i--) {
366
+ const j = Math.floor(Math.random() * (i + 1));
367
+ [array[i], array[j]] = [array[j], array[i]];
368
+ }
369
+ return array;
370
+ }
371
+ };
372
+ exports.ResourceLockService = ResourceLockService;
373
+ exports.ResourceLockService = ResourceLockService = ResourceLockService_1 = __decorate([
374
+ (0, common_1.Injectable)(),
375
+ __param(0, (0, common_1.Inject)(constants_1.ATOMIC_QUEUES_REDIS)),
376
+ __param(1, (0, common_1.Inject)(constants_1.ATOMIC_QUEUES_CONFIG)),
377
+ __metadata("design:paramtypes", [ioredis_1.default, Object])
378
+ ], ResourceLockService);
379
+ //# sourceMappingURL=resource-lock.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-lock.service.js","sourceRoot":"","sources":["../../../src/services/resource-lock/resource-lock.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './service-queue.service';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/service-queue/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./service-queue.service"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/service-queue/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC"}
@@ -0,0 +1,232 @@
1
+ import { OnModuleInit, OnApplicationShutdown } from '@nestjs/common';
2
+ import Redis from 'ioredis';
3
+ import { IAtomicQueuesModuleConfig } from '../../domain';
4
+ /**
5
+ * Service-level job names for global atomic operations.
6
+ * These operations MUST be processed by exactly ONE worker across the entire distributed system.
7
+ */
8
+ export declare enum ServiceQueueJobNames {
9
+ /** Get the count of all workers across all nodes */
10
+ GET_GLOBAL_WORKER_COUNT = "get-global-worker-count",
11
+ /** Get workers for a specific entity across all nodes */
12
+ GET_ENTITY_WORKERS = "get-entity-workers",
13
+ /** Verify ownership of a resource */
14
+ VERIFY_OWNERSHIP = "verify-ownership",
15
+ /** Acquire global lock */
16
+ ACQUIRE_GLOBAL_LOCK = "acquire-global-lock",
17
+ /** Release global lock */
18
+ RELEASE_GLOBAL_LOCK = "release-global-lock",
19
+ /** Run scaling cycle for CronManager - triggers worker spawn/terminate decisions */
20
+ RUN_SCALING_CYCLE = "run-scaling-cycle",
21
+ /** Spawn a worker for a specific entity - used when opening a table/entity */
22
+ SPAWN_ENTITY_WORKER = "spawn-entity-worker",
23
+ /** Custom service operation */
24
+ CUSTOM = "custom"
25
+ }
26
+ /**
27
+ * Job data for service queue operations
28
+ */
29
+ export interface IServiceQueueJobData<T = unknown> {
30
+ uuid: string;
31
+ jobName: ServiceQueueJobNames;
32
+ payload: T;
33
+ responseChannel?: string;
34
+ }
35
+ /**
36
+ * ServiceQueueManager
37
+ *
38
+ * Manages the global service-level queue for operations that MUST be atomic
39
+ * across the entire distributed system. Unlike per-entity queues that can have
40
+ * one worker per entity, the service queue has EXACTLY ONE worker globally.
41
+ *
42
+ * Use cases:
43
+ * - Querying global worker counts (can't race with worker creation/deletion)
44
+ * - Ownership verification for resources
45
+ * - Global state mutations
46
+ * - Cross-node coordination
47
+ *
48
+ * Architecture:
49
+ * - Uses a distributed lock to ensure only ONE service worker exists globally
50
+ * - The worker can run on ANY node
51
+ * - If the worker dies, another node will acquire the lock and spawn it
52
+ * - All operations go through the single queue for serialization
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * // Execute a global atomic operation
57
+ * const workerCount = await serviceQueue.executeServiceOperation(
58
+ * ServiceQueueJobNames.GET_GLOBAL_WORKER_COUNT,
59
+ * { entityType: 'table' },
60
+ * );
61
+ * ```
62
+ */
63
+ export declare class ServiceQueueManager implements OnModuleInit, OnApplicationShutdown {
64
+ private readonly redis;
65
+ private readonly config;
66
+ private readonly logger;
67
+ private readonly keyPrefix;
68
+ private readonly serviceQueueName;
69
+ private readonly serviceWorkerName;
70
+ private readonly lockKey;
71
+ private readonly lockTTL;
72
+ private readonly lockRenewalInterval;
73
+ private serviceQueue;
74
+ private serviceWorker;
75
+ private lockRenewalTimer;
76
+ private subscriberClient;
77
+ private hasLock;
78
+ private readonly nodeId;
79
+ private readonly pendingOperations;
80
+ private readonly customProcessors;
81
+ private scalingCycleHandler;
82
+ constructor(redis: Redis, config: IAtomicQueuesModuleConfig);
83
+ /**
84
+ * Initialize on module start.
85
+ * Attempts to acquire the global service worker lock.
86
+ */
87
+ onModuleInit(): Promise<void>;
88
+ /**
89
+ * Cleanup on shutdown.
90
+ */
91
+ onApplicationShutdown(): Promise<void>;
92
+ /**
93
+ * Execute a service-level operation atomically.
94
+ * This queues the operation to the service queue and waits for the result.
95
+ *
96
+ * @param jobName The type of operation to execute
97
+ * @param payload The operation payload
98
+ * @param timeoutMs Timeout in milliseconds (default: 30000)
99
+ * @returns The operation result
100
+ */
101
+ executeServiceOperation<T, R>(jobName: ServiceQueueJobNames, payload: T, timeoutMs?: number): Promise<R>;
102
+ /**
103
+ * Queue a service operation without waiting for result (fire-and-forget).
104
+ */
105
+ queueServiceOperation<T>(jobName: ServiceQueueJobNames, payload: T): Promise<string>;
106
+ /**
107
+ * Register a custom processor for service-level operations.
108
+ * This allows the consuming application to add custom atomic operations.
109
+ */
110
+ registerCustomProcessor(name: string, processor: (payload: unknown) => Promise<unknown>): void;
111
+ /**
112
+ * Check if this node is the service worker owner.
113
+ */
114
+ isServiceWorkerOwner(): boolean;
115
+ /**
116
+ * Register the scaling cycle handler (called by CronManager).
117
+ * This allows CronManager to register its internal scaling logic to be
118
+ * executed atomically by the service worker.
119
+ */
120
+ registerScalingCycleHandler(handler: (entityType: string) => Promise<unknown>): void;
121
+ /**
122
+ * Spawn worker handler type - directly spawns a worker for a specific entity.
123
+ */
124
+ private spawnWorkerHandler?;
125
+ /**
126
+ * Register the spawn worker handler (called by CronManager or TableWorkerScalingService).
127
+ * This allows directly spawning a worker for a specific entity without waiting
128
+ * for the next scaling cycle.
129
+ */
130
+ registerSpawnWorkerHandler(handler: (entityType: string, entityId: string) => Promise<void>): void;
131
+ /**
132
+ * Trigger a scaling cycle for an entity type.
133
+ * This queues the job to the service queue - only the service worker will execute it.
134
+ */
135
+ triggerScalingCycle(entityType: string): Promise<void>;
136
+ /**
137
+ * Request spawning a worker for a specific entity.
138
+ * This is used when an entity (e.g., table) is opened and needs a worker immediately,
139
+ * without waiting for the next scaling cycle.
140
+ *
141
+ * The job is processed by the service worker to ensure atomic operation.
142
+ *
143
+ * @param entityType The type of entity (e.g., 'table')
144
+ * @param entityId The ID of the entity (e.g., tableId)
145
+ */
146
+ requestSpawnEntityWorker(entityType: string, entityId: string): Promise<void>;
147
+ /**
148
+ * Get the service queue name.
149
+ */
150
+ getQueueName(): string;
151
+ /**
152
+ * Get the service worker name.
153
+ */
154
+ getWorkerName(): string;
155
+ /**
156
+ * Get pending job count in the service queue.
157
+ */
158
+ getQueueDepth(): Promise<number>;
159
+ /**
160
+ * Try to acquire the global service worker lock.
161
+ */
162
+ private tryAcquireServiceWorkerLock;
163
+ /**
164
+ * Release the service worker lock.
165
+ */
166
+ private releaseLock;
167
+ /**
168
+ * Start periodic lock renewal.
169
+ */
170
+ private startLockRenewal;
171
+ /**
172
+ * Start periodic lock acquisition attempts.
173
+ * Retries more frequently initially, then backs off to lockTTL interval.
174
+ */
175
+ private startLockAcquisitionLoop;
176
+ /**
177
+ * Start the service worker.
178
+ */
179
+ private startServiceWorker;
180
+ /**
181
+ * Stop the service worker.
182
+ */
183
+ private stopServiceWorker;
184
+ /**
185
+ * Process a service queue job.
186
+ */
187
+ private processServiceJob;
188
+ /**
189
+ * Wait for a response on a channel.
190
+ */
191
+ private waitForResponse;
192
+ /**
193
+ * Get global worker count across all nodes.
194
+ */
195
+ private handleGetGlobalWorkerCount;
196
+ /**
197
+ * Get workers for a specific entity.
198
+ * Uses the worker heartbeat TTL keys as the single source of truth.
199
+ */
200
+ private handleGetEntityWorkers;
201
+ /**
202
+ * Verify ownership of a resource.
203
+ */
204
+ private handleVerifyOwnership;
205
+ /**
206
+ * Acquire a global lock atomically.
207
+ */
208
+ private handleAcquireGlobalLock;
209
+ /**
210
+ * Release a global lock atomically.
211
+ */
212
+ private handleReleaseGlobalLock;
213
+ /**
214
+ * Handle custom operation by delegating to registered processor.
215
+ */
216
+ private handleCustomOperation;
217
+ /**
218
+ * Handle scaling cycle request by delegating to registered CronManager handler.
219
+ */
220
+ private handleRunScalingCycle;
221
+ /**
222
+ * Handle spawn entity worker request.
223
+ * This directly spawns a worker for the specific entity, bypassing the scaling cycle.
224
+ * Used when opening a table/entity that needs a worker immediately.
225
+ */
226
+ private handleSpawnEntityWorker;
227
+ /**
228
+ * Scan Redis keys matching a pattern.
229
+ */
230
+ private scanKeys;
231
+ }
232
+ //# sourceMappingURL=service-queue.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-queue.service.d.ts","sourceRoot":"","sources":["../../../src/services/service-queue/service-queue.service.ts"],"names":[],"mappings":"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"}