@nest-omni/core 2.0.1-8 → 3.1.1-10

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 (41) hide show
  1. package/common/dto/page-options.dto.d.ts +1 -1
  2. package/common/index.d.ts +0 -1
  3. package/common/index.js +0 -1
  4. package/decorators/controller.decorator.d.ts +1 -1
  5. package/decorators/property.decorators.js +1 -1
  6. package/decorators/timestamp-column.decorator.d.ts +1 -1
  7. package/decorators/user_auth.decorator.d.ts +1 -1
  8. package/health-checker/health-checker.controller.d.ts +2 -4
  9. package/health-checker/health-checker.controller.js +2 -5
  10. package/health-checker/health-checker.module.js +2 -3
  11. package/health-checker/index.d.ts +2 -0
  12. package/health-checker/index.js +18 -0
  13. package/helpers/date.helper.js +10 -10
  14. package/index.d.ts +4 -0
  15. package/index.js +4 -0
  16. package/package.json +142 -46
  17. package/setup/bootstrap.setup.js +37 -87
  18. package/setup/index.d.ts +5 -0
  19. package/setup/index.js +5 -0
  20. package/setup/mode.setup.d.ts +12 -0
  21. package/setup/mode.setup.js +60 -0
  22. package/setup/redis.lock.decorator.d.ts +5 -0
  23. package/setup/redis.lock.decorator.js +60 -0
  24. package/setup/redis.lock.service.d.ts +56 -0
  25. package/setup/redis.lock.service.js +338 -0
  26. package/setup/schedule.decorator.d.ts +21 -0
  27. package/setup/schedule.decorator.js +127 -0
  28. package/setup/worker.decorator.d.ts +14 -0
  29. package/setup/worker.decorator.js +130 -0
  30. package/shared/serviceRegistryModule.js +17 -19
  31. package/shared/services/api-config.service.d.ts +9 -8
  32. package/shared/services/api-config.service.js +55 -46
  33. package/validator-json/default.js +9 -1
  34. package/validators/is-exists.validator.js +0 -2
  35. package/validators/is-unique.validator.js +0 -2
  36. package/validators/skip-empty.validator.d.ts +1 -1
  37. package/common/abstract-client.service.d.ts +0 -16
  38. package/common/abstract-client.service.js +0 -35
  39. package/health-checker/health-indicators/service.indicator.d.ts +0 -8
  40. package/health-checker/health-indicators/service.indicator.js +0 -66
  41. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApplicationMode = void 0;
4
+ exports.getApplicationMode = getApplicationMode;
5
+ exports.shouldProcessQueues = shouldProcessQueues;
6
+ exports.shouldStartHttpServer = shouldStartHttpServer;
7
+ exports.isHttpMode = isHttpMode;
8
+ exports.isWorkerMode = isWorkerMode;
9
+ exports.isHybridMode = isHybridMode;
10
+ exports.getModeDescription = getModeDescription;
11
+ var ApplicationMode;
12
+ (function (ApplicationMode) {
13
+ ApplicationMode["HTTP"] = "http";
14
+ ApplicationMode["WORKER"] = "worker";
15
+ ApplicationMode["HYBRID"] = "hybrid";
16
+ })(ApplicationMode || (exports.ApplicationMode = ApplicationMode = {}));
17
+ function getApplicationMode() {
18
+ const mode = (process.env.APP_MODE || process.env.MODE || 'hybrid')
19
+ .toLowerCase()
20
+ .trim();
21
+ switch (mode) {
22
+ case 'http':
23
+ return ApplicationMode.HTTP;
24
+ case 'worker':
25
+ return ApplicationMode.WORKER;
26
+ case 'hybrid':
27
+ default:
28
+ return ApplicationMode.HYBRID;
29
+ }
30
+ }
31
+ function shouldProcessQueues() {
32
+ const mode = getApplicationMode();
33
+ return mode === ApplicationMode.WORKER || mode === ApplicationMode.HYBRID;
34
+ }
35
+ function shouldStartHttpServer() {
36
+ const mode = getApplicationMode();
37
+ return mode === ApplicationMode.HTTP || mode === ApplicationMode.HYBRID;
38
+ }
39
+ function isHttpMode() {
40
+ return getApplicationMode() === ApplicationMode.HTTP;
41
+ }
42
+ function isWorkerMode() {
43
+ return getApplicationMode() === ApplicationMode.WORKER;
44
+ }
45
+ function isHybridMode() {
46
+ return getApplicationMode() === ApplicationMode.HYBRID;
47
+ }
48
+ function getModeDescription() {
49
+ const mode = getApplicationMode();
50
+ switch (mode) {
51
+ case ApplicationMode.HTTP:
52
+ return 'HTTP-only mode (no background workers)';
53
+ case ApplicationMode.WORKER:
54
+ return 'Worker-only mode (no HTTP server)';
55
+ case ApplicationMode.HYBRID:
56
+ return 'Hybrid mode (HTTP server + background workers)';
57
+ default:
58
+ return 'Unknown mode';
59
+ }
60
+ }
@@ -0,0 +1,5 @@
1
+ import type { LockOptions } from './redis.lock.service';
2
+ export declare function UseRedisLock(lockKey: string, options?: LockOptions & {
3
+ skipReturnValue?: any;
4
+ }): MethodDecorator;
5
+ export declare function UseRedisLockOrSkip(lockKey: string, ttl?: number): MethodDecorator;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.UseRedisLock = UseRedisLock;
13
+ exports.UseRedisLockOrSkip = UseRedisLockOrSkip;
14
+ const common_1 = require("@nestjs/common");
15
+ function UseRedisLock(lockKey, options = {}) {
16
+ return function (target, propertyKey, descriptor) {
17
+ const originalMethod = descriptor.value;
18
+ const logger = new common_1.Logger(`RedisLock:${String(propertyKey)}`);
19
+ descriptor.value = function (...args) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ var _a;
22
+ const { RedisLockService } = yield Promise.resolve().then(() => require('./redis.lock.service'));
23
+ const lockService = RedisLockService.getGlobalInstance();
24
+ if (!lockService) {
25
+ logger.error(`RedisLockService global instance not found. ` +
26
+ `Please ensure RedisLockService is registered in your application module.`);
27
+ throw new Error(`RedisLockService not initialized. Please register it in your module.`);
28
+ }
29
+ const skipReturnValue = (_a = options.skipReturnValue) !== null && _a !== void 0 ? _a : null;
30
+ const lockResult = yield lockService.acquireLock(lockKey, options);
31
+ if (!lockResult.acquired) {
32
+ logger.log(`Lock '${lockKey}' is already held, skipping execution of ${String(propertyKey)}`);
33
+ return skipReturnValue;
34
+ }
35
+ logger.debug(`Lock '${lockKey}' acquired, executing ${String(propertyKey)}`);
36
+ try {
37
+ return yield originalMethod.apply(this, args);
38
+ }
39
+ catch (error) {
40
+ logger.error(`Error executing ${String(propertyKey)} with lock '${lockKey}':`, error);
41
+ throw error;
42
+ }
43
+ finally {
44
+ if (lockResult.autoExtendTimer) {
45
+ clearInterval(lockResult.autoExtendTimer);
46
+ }
47
+ yield lockService.releaseLock(lockKey, lockResult.lockValue, options.keyPrefix);
48
+ logger.debug(`Lock '${lockKey}' released`);
49
+ }
50
+ });
51
+ };
52
+ return descriptor;
53
+ };
54
+ }
55
+ function UseRedisLockOrSkip(lockKey, ttl = 300000) {
56
+ return UseRedisLock(lockKey, {
57
+ ttl,
58
+ skipReturnValue: false,
59
+ });
60
+ }
@@ -0,0 +1,56 @@
1
+ import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
+ export interface LockOptions {
3
+ ttl?: number;
4
+ retryCount?: number;
5
+ retryDelay?: number;
6
+ keyPrefix?: string;
7
+ throwOnFailure?: boolean;
8
+ autoExtend?: number;
9
+ }
10
+ export interface LockResult {
11
+ acquired: boolean;
12
+ lockValue?: string;
13
+ error?: string;
14
+ autoExtendTimer?: NodeJS.Timeout;
15
+ }
16
+ export interface RedisOptions {
17
+ host?: string;
18
+ port?: number;
19
+ password?: string;
20
+ db?: number;
21
+ retryDelay?: number;
22
+ maxRetries?: number;
23
+ reconnectOnError?: (err: Error) => boolean;
24
+ }
25
+ export declare class RedisLockService implements OnModuleInit, OnModuleDestroy {
26
+ private static globalInstance;
27
+ private readonly logger;
28
+ private redis;
29
+ private redisOptions;
30
+ private isConnected;
31
+ private isConnecting;
32
+ private connectionPromise;
33
+ private readonly defaultOptions;
34
+ private readonly defaultRedisOptions;
35
+ constructor(redisOptions?: RedisOptions);
36
+ static getGlobalInstance(): RedisLockService | null;
37
+ static setGlobalInstance(instance: RedisLockService): void;
38
+ onModuleInit(): Promise<void>;
39
+ onModuleDestroy(): Promise<void>;
40
+ acquireLock(key: string, options?: LockOptions): Promise<LockResult>;
41
+ releaseLock(key: string, lockValue: string, keyPrefix?: string): Promise<boolean>;
42
+ extendLock(key: string, lockValue: string, ttl: number, keyPrefix?: string): Promise<boolean>;
43
+ isLocked(key: string, keyPrefix?: string): Promise<boolean>;
44
+ withLock<T>(key: string, fn: () => Promise<T>, options?: LockOptions): Promise<T | null>;
45
+ getLockInfo(key: string, keyPrefix?: string): Promise<{
46
+ value: string | null;
47
+ ttl: number | null;
48
+ }>;
49
+ forceRelease(key: string, keyPrefix?: string): Promise<boolean>;
50
+ getRedisOptions(): RedisOptions;
51
+ private getRedis;
52
+ private createRedisConnection;
53
+ private generateLockValue;
54
+ private buildLockKey;
55
+ private sleep;
56
+ }
@@ -0,0 +1,338 @@
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var RedisLockService_1;
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.RedisLockService = void 0;
23
+ const common_1 = require("@nestjs/common");
24
+ const ioredis_1 = require("ioredis");
25
+ let RedisLockService = RedisLockService_1 = class RedisLockService {
26
+ constructor(redisOptions) {
27
+ this.logger = new common_1.Logger(RedisLockService_1.name);
28
+ this.redis = null;
29
+ this.isConnected = false;
30
+ this.isConnecting = false;
31
+ this.connectionPromise = null;
32
+ this.defaultOptions = {
33
+ ttl: 300000,
34
+ retryCount: 0,
35
+ retryDelay: 100,
36
+ keyPrefix: 'lock',
37
+ throwOnFailure: false,
38
+ autoExtend: 0,
39
+ };
40
+ this.defaultRedisOptions = {
41
+ host: process.env.REDIS_HOST || 'localhost',
42
+ port: parseInt(process.env.REDIS_PORT || '6379', 10),
43
+ password: process.env.REDIS_PASSWORD,
44
+ db: parseInt(process.env.REDIS_DB || '0', 10),
45
+ retryDelay: 2000,
46
+ maxRetries: 10,
47
+ reconnectOnError: (err) => {
48
+ this.logger.warn('Redis reconnection error:', err.message);
49
+ return true;
50
+ },
51
+ };
52
+ this.redisOptions = Object.assign(Object.assign({}, this.defaultRedisOptions), redisOptions);
53
+ if (!RedisLockService_1.globalInstance) {
54
+ RedisLockService_1.globalInstance = this;
55
+ }
56
+ }
57
+ static getGlobalInstance() {
58
+ return RedisLockService_1.globalInstance;
59
+ }
60
+ static setGlobalInstance(instance) {
61
+ RedisLockService_1.globalInstance = instance;
62
+ }
63
+ onModuleInit() {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ this.logger.log('RedisLockService initialized, will connect on first use');
66
+ });
67
+ }
68
+ onModuleDestroy() {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ if (this.redis) {
71
+ yield this.redis.quit();
72
+ this.isConnected = false;
73
+ this.logger.log('Redis connection closed');
74
+ }
75
+ });
76
+ }
77
+ acquireLock(key_1) {
78
+ return __awaiter(this, arguments, void 0, function* (key, options = {}) {
79
+ const redis = yield this.getRedis();
80
+ const opts = Object.assign(Object.assign({}, this.defaultOptions), options);
81
+ const lockKey = this.buildLockKey(key, opts.keyPrefix);
82
+ const lockValue = this.generateLockValue();
83
+ let attempts = 0;
84
+ const maxAttempts = opts.retryCount + 1;
85
+ while (attempts < maxAttempts) {
86
+ try {
87
+ const result = yield redis.set(lockKey, lockValue, 'PX', opts.ttl, 'NX');
88
+ if (result === 'OK') {
89
+ this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms)`);
90
+ let autoExtendTimer;
91
+ if (opts.autoExtend && opts.autoExtend > 0) {
92
+ autoExtendTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
93
+ try {
94
+ yield this.extendLock(key, lockValue, opts.ttl, opts.keyPrefix);
95
+ }
96
+ catch (error) {
97
+ this.logger.error(`Failed to auto-extend lock ${lockKey}:`, error);
98
+ }
99
+ }), opts.autoExtend);
100
+ }
101
+ return { acquired: true, lockValue, autoExtendTimer };
102
+ }
103
+ attempts++;
104
+ if (attempts < maxAttempts) {
105
+ this.logger.debug(`Lock acquisition failed for ${lockKey}, retrying... (${attempts}/${opts.retryCount})`);
106
+ yield this.sleep(opts.retryDelay);
107
+ }
108
+ }
109
+ catch (error) {
110
+ const errorMessage = `Error acquiring lock for ${lockKey}: ${error.message}`;
111
+ this.logger.error(errorMessage, error.stack);
112
+ if (opts.throwOnFailure) {
113
+ throw new Error(errorMessage);
114
+ }
115
+ return { acquired: false, error: errorMessage };
116
+ }
117
+ }
118
+ const failureMessage = `Failed to acquire lock for ${lockKey} after ${attempts} attempts`;
119
+ this.logger.warn(failureMessage);
120
+ if (opts.throwOnFailure) {
121
+ throw new Error(failureMessage);
122
+ }
123
+ return { acquired: false, error: failureMessage };
124
+ });
125
+ }
126
+ releaseLock(key_1, lockValue_1) {
127
+ return __awaiter(this, arguments, void 0, function* (key, lockValue, keyPrefix = 'lock') {
128
+ const redis = yield this.getRedis();
129
+ const lockKey = this.buildLockKey(key, keyPrefix);
130
+ try {
131
+ const script = `
132
+ if redis.call("get", KEYS[1]) == ARGV[1] then
133
+ return redis.call("del", KEYS[1])
134
+ else
135
+ return 0
136
+ end
137
+ `;
138
+ const result = yield redis.eval(script, 1, lockKey, lockValue);
139
+ if (result === 1) {
140
+ this.logger.debug(`Lock released: ${lockKey}`);
141
+ return true;
142
+ }
143
+ else {
144
+ this.logger.warn(`Lock release failed: ${lockKey} (lock value mismatch or already expired)`);
145
+ return false;
146
+ }
147
+ }
148
+ catch (error) {
149
+ this.logger.error(`Error releasing lock for ${lockKey}: ${error.message}`, error.stack);
150
+ return false;
151
+ }
152
+ });
153
+ }
154
+ extendLock(key_1, lockValue_1, ttl_1) {
155
+ return __awaiter(this, arguments, void 0, function* (key, lockValue, ttl, keyPrefix = 'lock') {
156
+ const redis = yield this.getRedis();
157
+ const lockKey = this.buildLockKey(key, keyPrefix);
158
+ try {
159
+ const script = `
160
+ if redis.call("get", KEYS[1]) == ARGV[1] then
161
+ return redis.call("pexpire", KEYS[1], ARGV[2])
162
+ else
163
+ return 0
164
+ end
165
+ `;
166
+ const result = yield redis.eval(script, 1, lockKey, lockValue, ttl);
167
+ if (result === 1) {
168
+ this.logger.debug(`Lock extended: ${lockKey} (new ttl: ${ttl}ms)`);
169
+ return true;
170
+ }
171
+ else {
172
+ this.logger.warn(`Lock extension failed: ${lockKey} (lock value mismatch or doesn't exist)`);
173
+ return false;
174
+ }
175
+ }
176
+ catch (error) {
177
+ this.logger.error(`Error extending lock for ${lockKey}: ${error.message}`, error.stack);
178
+ return false;
179
+ }
180
+ });
181
+ }
182
+ isLocked(key_1) {
183
+ return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
184
+ const redis = yield this.getRedis();
185
+ const lockKey = this.buildLockKey(key, keyPrefix);
186
+ try {
187
+ const exists = yield redis.exists(lockKey);
188
+ return exists === 1;
189
+ }
190
+ catch (error) {
191
+ this.logger.error(`Error checking lock existence for ${lockKey}: ${error.message}`, error.stack);
192
+ return false;
193
+ }
194
+ });
195
+ }
196
+ withLock(key_1, fn_1) {
197
+ return __awaiter(this, arguments, void 0, function* (key, fn, options = {}) {
198
+ const lockResult = yield this.acquireLock(key, options);
199
+ if (!lockResult.acquired) {
200
+ this.logger.warn(`Could not acquire lock for ${key}, skipping execution`);
201
+ return null;
202
+ }
203
+ try {
204
+ return yield fn();
205
+ }
206
+ catch (error) {
207
+ this.logger.error(`Error executing function with lock ${key}:`, error);
208
+ throw error;
209
+ }
210
+ finally {
211
+ if (lockResult.autoExtendTimer) {
212
+ clearInterval(lockResult.autoExtendTimer);
213
+ }
214
+ yield this.releaseLock(key, lockResult.lockValue, options.keyPrefix);
215
+ }
216
+ });
217
+ }
218
+ getLockInfo(key_1) {
219
+ return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
220
+ const redis = yield this.getRedis();
221
+ const lockKey = this.buildLockKey(key, keyPrefix);
222
+ try {
223
+ const [value, ttl] = yield Promise.all([
224
+ redis.get(lockKey),
225
+ redis.pttl(lockKey),
226
+ ]);
227
+ return {
228
+ value,
229
+ ttl: ttl >= 0 ? ttl : null,
230
+ };
231
+ }
232
+ catch (error) {
233
+ this.logger.error(`Error getting lock info for ${lockKey}: ${error.message}`, error.stack);
234
+ return { value: null, ttl: null };
235
+ }
236
+ });
237
+ }
238
+ forceRelease(key_1) {
239
+ return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
240
+ const redis = yield this.getRedis();
241
+ const lockKey = this.buildLockKey(key, keyPrefix);
242
+ try {
243
+ const result = yield redis.del(lockKey);
244
+ if (result === 1) {
245
+ this.logger.debug(`Lock forcefully released: ${lockKey}`);
246
+ return true;
247
+ }
248
+ else {
249
+ this.logger.debug(`No lock found to forcefully release: ${lockKey}`);
250
+ return false;
251
+ }
252
+ }
253
+ catch (error) {
254
+ this.logger.error(`Error force releasing lock for ${lockKey}: ${error.message}`, error.stack);
255
+ return false;
256
+ }
257
+ });
258
+ }
259
+ getRedisOptions() {
260
+ return Object.assign({}, this.redisOptions);
261
+ }
262
+ getRedis() {
263
+ return __awaiter(this, void 0, void 0, function* () {
264
+ if (this.redis && this.isConnected) {
265
+ return this.redis;
266
+ }
267
+ if (this.isConnecting && this.connectionPromise) {
268
+ return this.connectionPromise;
269
+ }
270
+ this.isConnecting = true;
271
+ this.connectionPromise = this.createRedisConnection()
272
+ .then((redis) => {
273
+ this.isConnecting = false;
274
+ this.isConnected = true;
275
+ return redis;
276
+ })
277
+ .catch((error) => {
278
+ this.isConnecting = false;
279
+ this.connectionPromise = null;
280
+ throw error;
281
+ });
282
+ return this.connectionPromise;
283
+ });
284
+ }
285
+ createRedisConnection() {
286
+ return __awaiter(this, void 0, void 0, function* () {
287
+ return new Promise((resolve, reject) => {
288
+ const redis = new ioredis_1.default({
289
+ host: this.redisOptions.host,
290
+ port: this.redisOptions.port,
291
+ password: this.redisOptions.password,
292
+ db: this.redisOptions.db,
293
+ retryStrategy: (times) => {
294
+ this.logger.warn(`Redis connection retry attempt ${times}`);
295
+ if (times > (this.redisOptions.maxRetries || 10)) {
296
+ this.logger.error('Max retries reached, giving up on Redis connection');
297
+ this.isConnected = false;
298
+ return undefined;
299
+ }
300
+ const delay = Math.min(times * (this.redisOptions.retryDelay || 2000), 30000);
301
+ this.logger.log(`Retrying Redis connection in ${delay}ms`);
302
+ return delay;
303
+ },
304
+ reconnectOnError: this.redisOptions.reconnectOnError,
305
+ });
306
+ const onConnect = () => {
307
+ this.logger.log(`Connected to Redis at ${this.redisOptions.host}:${this.redisOptions.port}`);
308
+ this.isConnected = true;
309
+ resolve(redis);
310
+ };
311
+ const onError = (err) => {
312
+ this.logger.error('Redis connection error:', err.message);
313
+ if (!this.isConnected) {
314
+ reject(err);
315
+ }
316
+ };
317
+ redis.once('connect', onConnect);
318
+ redis.once('error', onError);
319
+ this.redis = redis;
320
+ });
321
+ });
322
+ }
323
+ generateLockValue() {
324
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}-${process.pid}`;
325
+ }
326
+ buildLockKey(key, prefix = 'lock') {
327
+ return `${prefix}:${key}`;
328
+ }
329
+ sleep(ms) {
330
+ return new Promise((resolve) => setTimeout(resolve, ms));
331
+ }
332
+ };
333
+ exports.RedisLockService = RedisLockService;
334
+ RedisLockService.globalInstance = null;
335
+ exports.RedisLockService = RedisLockService = RedisLockService_1 = __decorate([
336
+ (0, common_1.Injectable)(),
337
+ __metadata("design:paramtypes", [Object])
338
+ ], RedisLockService);
@@ -0,0 +1,21 @@
1
+ import type { CronOptions } from '@nestjs/schedule';
2
+ export declare function WorkerCron(cronTime: string | Date, options?: CronOptions): MethodDecorator;
3
+ export declare function WorkerInterval(timeout: number, options?: {
4
+ name?: string;
5
+ }): MethodDecorator;
6
+ export declare function WorkerTimeout(timeout: number, options?: {
7
+ name?: string;
8
+ }): MethodDecorator;
9
+ export declare function WorkerCronWithLock(cronTime: string | Date, lockKey: string, lockTtl?: number, cronOptions?: CronOptions): MethodDecorator;
10
+ export declare function WorkerIntervalWithLock(timeout: number, lockKey: string, lockTtl?: number, intervalOptions?: {
11
+ name?: string;
12
+ }): MethodDecorator;
13
+ export declare function WorkerTimeoutWithLock(timeout: number, lockKey: string, lockTtl?: number, timeoutOptions?: {
14
+ name?: string;
15
+ }): MethodDecorator;
16
+ export declare function WorkerCronAdvanced(cronTime: string | Date, lockKey: string, options?: {
17
+ lockTtl?: number;
18
+ cronOptions?: CronOptions;
19
+ logExecution?: boolean;
20
+ onError?: (error: Error) => void;
21
+ }): MethodDecorator;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.WorkerCron = WorkerCron;
13
+ exports.WorkerInterval = WorkerInterval;
14
+ exports.WorkerTimeout = WorkerTimeout;
15
+ exports.WorkerCronWithLock = WorkerCronWithLock;
16
+ exports.WorkerIntervalWithLock = WorkerIntervalWithLock;
17
+ exports.WorkerTimeoutWithLock = WorkerTimeoutWithLock;
18
+ exports.WorkerCronAdvanced = WorkerCronAdvanced;
19
+ const schedule_1 = require("@nestjs/schedule");
20
+ const mode_setup_1 = require("./mode.setup");
21
+ const redis_lock_decorator_1 = require("./redis.lock.decorator");
22
+ const common_1 = require("@nestjs/common");
23
+ function WorkerCron(cronTime, options) {
24
+ if ((0, mode_setup_1.shouldProcessQueues)()) {
25
+ return (0, schedule_1.Cron)(cronTime, options);
26
+ }
27
+ return function (target, propertyKey, descriptor) {
28
+ return descriptor;
29
+ };
30
+ }
31
+ function WorkerInterval(timeout, options) {
32
+ if ((0, mode_setup_1.shouldProcessQueues)()) {
33
+ return (0, schedule_1.Interval)((options === null || options === void 0 ? void 0 : options.name) || `interval-${timeout}`, timeout);
34
+ }
35
+ return function (target, propertyKey, descriptor) {
36
+ return descriptor;
37
+ };
38
+ }
39
+ function WorkerTimeout(timeout, options) {
40
+ if ((0, mode_setup_1.shouldProcessQueues)()) {
41
+ return (0, schedule_1.Timeout)((options === null || options === void 0 ? void 0 : options.name) || `timeout-${timeout}`, timeout);
42
+ }
43
+ return function (target, propertyKey, descriptor) {
44
+ return descriptor;
45
+ };
46
+ }
47
+ function WorkerCronWithLock(cronTime, lockKey, lockTtl = 300000, cronOptions) {
48
+ if (!(0, mode_setup_1.shouldProcessQueues)()) {
49
+ return function (target, propertyKey, descriptor) {
50
+ return descriptor;
51
+ };
52
+ }
53
+ return function (target, propertyKey, descriptor) {
54
+ (0, schedule_1.Cron)(cronTime, cronOptions)(target, propertyKey, descriptor);
55
+ (0, redis_lock_decorator_1.UseRedisLockOrSkip)(lockKey, lockTtl)(target, propertyKey, descriptor);
56
+ return descriptor;
57
+ };
58
+ }
59
+ function WorkerIntervalWithLock(timeout, lockKey, lockTtl, intervalOptions) {
60
+ if (!(0, mode_setup_1.shouldProcessQueues)()) {
61
+ return function (target, propertyKey, descriptor) {
62
+ return descriptor;
63
+ };
64
+ }
65
+ const ttl = lockTtl !== null && lockTtl !== void 0 ? lockTtl : timeout;
66
+ return function (target, propertyKey, descriptor) {
67
+ (0, schedule_1.Interval)((intervalOptions === null || intervalOptions === void 0 ? void 0 : intervalOptions.name) || `interval-with-lock-${timeout}`, timeout)(target, propertyKey, descriptor);
68
+ (0, redis_lock_decorator_1.UseRedisLockOrSkip)(lockKey, ttl)(target, propertyKey, descriptor);
69
+ return descriptor;
70
+ };
71
+ }
72
+ function WorkerTimeoutWithLock(timeout, lockKey, lockTtl = 300000, timeoutOptions) {
73
+ if (!(0, mode_setup_1.shouldProcessQueues)()) {
74
+ return function (target, propertyKey, descriptor) {
75
+ return descriptor;
76
+ };
77
+ }
78
+ return function (target, propertyKey, descriptor) {
79
+ (0, schedule_1.Timeout)((timeoutOptions === null || timeoutOptions === void 0 ? void 0 : timeoutOptions.name) || `timeout-with-lock-${timeout}`, timeout)(target, propertyKey, descriptor);
80
+ (0, redis_lock_decorator_1.UseRedisLockOrSkip)(lockKey, lockTtl)(target, propertyKey, descriptor);
81
+ return descriptor;
82
+ };
83
+ }
84
+ function WorkerCronAdvanced(cronTime, lockKey, options = {}) {
85
+ if (!(0, mode_setup_1.shouldProcessQueues)()) {
86
+ return function (target, propertyKey, descriptor) {
87
+ return descriptor;
88
+ };
89
+ }
90
+ const { lockTtl = 300000, cronOptions, logExecution = true, onError, } = options;
91
+ return function (target, propertyKey, descriptor) {
92
+ const originalMethod = descriptor.value;
93
+ const logger = new common_1.Logger(`Scheduler:${String(propertyKey)}`);
94
+ descriptor.value = function (...args) {
95
+ return __awaiter(this, void 0, void 0, function* () {
96
+ const startTime = Date.now();
97
+ try {
98
+ if (logExecution) {
99
+ logger.log(`Starting scheduled task: ${String(propertyKey)}`);
100
+ }
101
+ const result = yield originalMethod.apply(this, args);
102
+ if (logExecution) {
103
+ const duration = Date.now() - startTime;
104
+ logger.log(`Completed scheduled task: ${String(propertyKey)} (${duration}ms)`);
105
+ }
106
+ return result;
107
+ }
108
+ catch (error) {
109
+ const duration = Date.now() - startTime;
110
+ logger.error(`Error in scheduled task: ${String(propertyKey)} (${duration}ms)`, error.stack);
111
+ if (onError) {
112
+ try {
113
+ onError(error);
114
+ }
115
+ catch (handlerError) {
116
+ logger.error('Error handler threw an error:', handlerError);
117
+ }
118
+ }
119
+ throw error;
120
+ }
121
+ });
122
+ };
123
+ (0, schedule_1.Cron)(cronTime, cronOptions)(target, propertyKey, descriptor);
124
+ (0, redis_lock_decorator_1.UseRedisLockOrSkip)(lockKey, lockTtl)(target, propertyKey, descriptor);
125
+ return descriptor;
126
+ };
127
+ }