@nest-omni/core 3.1.1-17 → 3.1.1-19

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 (40) hide show
  1. package/cache/cache-serialization.service.d.ts +4 -11
  2. package/cache/cache-serialization.service.js +29 -124
  3. package/cache/cache.constants.d.ts +2 -0
  4. package/cache/cache.constants.js +5 -0
  5. package/cache/cache.module.d.ts +2 -0
  6. package/cache/cache.module.js +49 -3
  7. package/cache/cache.service.d.ts +3 -1
  8. package/cache/cache.service.js +32 -4
  9. package/cache/examples/basic-usage.d.ts +58 -0
  10. package/cache/examples/basic-usage.js +379 -0
  11. package/cache/index.d.ts +2 -1
  12. package/cache/index.js +4 -1
  13. package/common/boilerplate.polyfill.d.ts +1 -7
  14. package/common/boilerplate.polyfill.js +1 -1
  15. package/common/dto/page-options.dto.d.ts +0 -3
  16. package/common/dto/page-options.dto.js +0 -12
  17. package/common/examples/paginate-and-map.example.d.ts +14 -0
  18. package/common/examples/paginate-and-map.example.js +158 -0
  19. package/decorators/examples/validation-decorators.example.d.ts +69 -0
  20. package/decorators/examples/validation-decorators.example.js +331 -0
  21. package/decorators/validator.decorators.d.ts +8 -1
  22. package/decorators/validator.decorators.js +115 -0
  23. package/i18n/en_US/validation.json +4 -1
  24. package/i18n/zh_CN/validation.json +4 -1
  25. package/index.d.ts +1 -0
  26. package/index.js +1 -0
  27. package/package.json +1 -1
  28. package/redis-lock/examples/lock-strategy.examples.d.ts +73 -0
  29. package/redis-lock/examples/lock-strategy.examples.js +387 -0
  30. package/redis-lock/index.d.ts +2 -2
  31. package/redis-lock/index.js +4 -1
  32. package/redis-lock/redis-lock.decorator.d.ts +4 -0
  33. package/redis-lock/redis-lock.decorator.js +43 -7
  34. package/redis-lock/redis-lock.service.d.ts +19 -0
  35. package/redis-lock/redis-lock.service.js +131 -6
  36. package/setup/bootstrap.setup.d.ts +0 -1
  37. package/setup/bootstrap.setup.js +0 -1
  38. package/setup/index.d.ts +0 -1
  39. package/setup/index.js +0 -1
  40. package/shared/serviceRegistryModule.js +2 -0
@@ -19,8 +19,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
19
19
  };
20
20
  var RedisLockService_1;
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.RedisLockService = void 0;
22
+ exports.RedisLockService = exports.LockStrategy = void 0;
23
23
  const common_1 = require("@nestjs/common");
24
+ var LockStrategy;
25
+ (function (LockStrategy) {
26
+ LockStrategy["SKIP"] = "SKIP";
27
+ LockStrategy["THROW"] = "THROW";
28
+ LockStrategy["WAIT"] = "WAIT";
29
+ })(LockStrategy || (exports.LockStrategy = LockStrategy = {}));
24
30
  let RedisLockService = RedisLockService_1 = class RedisLockService {
25
31
  constructor() {
26
32
  this.logger = new common_1.Logger(RedisLockService_1.name);
@@ -31,6 +37,8 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
31
37
  retryDelay: 100,
32
38
  keyPrefix: 'lock',
33
39
  throwOnFailure: false,
40
+ strategy: LockStrategy.SKIP,
41
+ waitTimeout: undefined,
34
42
  autoExtend: 0,
35
43
  };
36
44
  if (!RedisLockService_1.globalInstance) {
@@ -84,15 +92,33 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
84
92
  return __awaiter(this, arguments, void 0, function* (key, options = {}) {
85
93
  const redis = yield this.getRedis();
86
94
  const opts = Object.assign(Object.assign({}, this.defaultOptions), options);
95
+ if (opts.throwOnFailure && !options.strategy) {
96
+ opts.strategy = LockStrategy.THROW;
97
+ }
87
98
  const lockKey = this.buildLockKey(key, opts.keyPrefix);
88
99
  const lockValue = this.generateLockValue();
100
+ let maxAttempts;
101
+ if (opts.strategy === LockStrategy.WAIT) {
102
+ maxAttempts = Number.MAX_SAFE_INTEGER;
103
+ }
104
+ else {
105
+ maxAttempts = opts.retryCount + 1;
106
+ }
89
107
  let attempts = 0;
90
- const maxAttempts = opts.retryCount + 1;
108
+ const startTime = Date.now();
91
109
  while (attempts < maxAttempts) {
110
+ if (opts.strategy === LockStrategy.WAIT && opts.waitTimeout) {
111
+ const elapsed = Date.now() - startTime;
112
+ if (elapsed >= opts.waitTimeout) {
113
+ const timeoutMessage = `Lock acquisition timed out for ${lockKey} after ${elapsed}ms (waitTimeout: ${opts.waitTimeout}ms)`;
114
+ this.logger.warn(timeoutMessage);
115
+ return { acquired: false, error: timeoutMessage };
116
+ }
117
+ }
92
118
  try {
93
119
  const result = yield redis.set(lockKey, lockValue, 'PX', opts.ttl, 'NX');
94
120
  if (result === 'OK') {
95
- this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms)`);
121
+ this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms, attempts: ${attempts + 1})`);
96
122
  let autoExtendTimer;
97
123
  if (opts.autoExtend && opts.autoExtend > 0) {
98
124
  autoExtendTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
@@ -107,15 +133,22 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
107
133
  return { acquired: true, lockValue, autoExtendTimer };
108
134
  }
109
135
  attempts++;
110
- if (attempts < maxAttempts) {
136
+ if (opts.strategy === LockStrategy.WAIT) {
137
+ if (attempts === 1 || attempts % 10 === 0) {
138
+ this.logger.debug(`Waiting for lock ${lockKey}... (attempt ${attempts})`);
139
+ }
140
+ }
141
+ else if (attempts < maxAttempts) {
111
142
  this.logger.debug(`Lock acquisition failed for ${lockKey}, retrying... (${attempts}/${opts.retryCount})`);
143
+ }
144
+ if (attempts < maxAttempts) {
112
145
  yield this.sleep(opts.retryDelay);
113
146
  }
114
147
  }
115
148
  catch (error) {
116
149
  const errorMessage = `Error acquiring lock for ${lockKey}: ${error.message}`;
117
150
  this.logger.error(errorMessage, error.stack);
118
- if (opts.throwOnFailure) {
151
+ if (opts.strategy === LockStrategy.THROW) {
119
152
  throw new Error(errorMessage);
120
153
  }
121
154
  return { acquired: false, error: errorMessage };
@@ -123,7 +156,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
123
156
  }
124
157
  const failureMessage = `Failed to acquire lock for ${lockKey} after ${attempts} attempts`;
125
158
  this.logger.warn(failureMessage);
126
- if (opts.throwOnFailure) {
159
+ if (opts.strategy === LockStrategy.THROW) {
127
160
  throw new Error(failureMessage);
128
161
  }
129
162
  return { acquired: false, error: failureMessage };
@@ -262,6 +295,98 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
262
295
  }
263
296
  });
264
297
  }
298
+ cleanupLocksByPattern(pattern_1) {
299
+ return __awaiter(this, arguments, void 0, function* (pattern, keyPrefix = 'lock') {
300
+ const redis = yield this.getRedis();
301
+ const searchPattern = `${keyPrefix}:${pattern}`;
302
+ try {
303
+ const keys = yield redis.keys(searchPattern);
304
+ if (keys.length === 0) {
305
+ this.logger.debug(`No locks found matching pattern: ${searchPattern}`);
306
+ return 0;
307
+ }
308
+ const result = yield redis.del(...keys);
309
+ this.logger.log(`Cleaned up ${result} lock(s) matching pattern: ${searchPattern}`);
310
+ return result;
311
+ }
312
+ catch (error) {
313
+ this.logger.error(`Error cleaning up locks by pattern ${searchPattern}: ${error.message}`, error.stack);
314
+ return 0;
315
+ }
316
+ });
317
+ }
318
+ cleanupOnStartup(patterns_1) {
319
+ return __awaiter(this, arguments, void 0, function* (patterns, keyPrefix = 'lock') {
320
+ this.logger.log(`Starting lock cleanup for ${patterns.length} pattern(s) on startup...`);
321
+ let totalDeleted = 0;
322
+ for (const pattern of patterns) {
323
+ const deleted = yield this.cleanupLocksByPattern(pattern, keyPrefix);
324
+ totalDeleted += deleted;
325
+ }
326
+ this.logger.log(`Startup lock cleanup completed. Deleted ${totalDeleted} lock(s)`);
327
+ return totalDeleted;
328
+ });
329
+ }
330
+ healthCheck() {
331
+ return __awaiter(this, void 0, void 0, function* () {
332
+ try {
333
+ const redis = yield this.getRedis();
334
+ const pong = yield redis.ping();
335
+ if (pong === 'PONG') {
336
+ return {
337
+ healthy: true,
338
+ redis: true,
339
+ message: 'Redis Lock Service is healthy',
340
+ };
341
+ }
342
+ else {
343
+ return {
344
+ healthy: false,
345
+ redis: false,
346
+ message: 'Redis ping returned unexpected response',
347
+ };
348
+ }
349
+ }
350
+ catch (error) {
351
+ return {
352
+ healthy: false,
353
+ redis: false,
354
+ message: `Redis Lock Service unhealthy: ${error.message}`,
355
+ };
356
+ }
357
+ });
358
+ }
359
+ getActiveLocks() {
360
+ return __awaiter(this, arguments, void 0, function* (pattern = '*', keyPrefix = 'lock') {
361
+ const redis = yield this.getRedis();
362
+ const searchPattern = `${keyPrefix}:${pattern}`;
363
+ try {
364
+ const keys = yield redis.keys(searchPattern);
365
+ if (keys.length === 0) {
366
+ return [];
367
+ }
368
+ const locks = yield Promise.all(keys.map((key) => __awaiter(this, void 0, void 0, function* () {
369
+ const [value, ttl] = yield Promise.all([
370
+ redis.get(key),
371
+ redis.pttl(key),
372
+ ]);
373
+ const cleanKey = key.startsWith(`${keyPrefix}:`)
374
+ ? key.substring(`${keyPrefix}:`.length)
375
+ : key;
376
+ return {
377
+ key: cleanKey,
378
+ value,
379
+ ttl: ttl >= 0 ? ttl : null,
380
+ };
381
+ })));
382
+ return locks.filter((lock) => lock.value !== null);
383
+ }
384
+ catch (error) {
385
+ this.logger.error(`Error getting active locks: ${error.message}`, error.stack);
386
+ return [];
387
+ }
388
+ });
389
+ }
265
390
  getRedis() {
266
391
  return __awaiter(this, void 0, void 0, function* () {
267
392
  if (!this.redis) {
@@ -1,3 +1,2 @@
1
- import '../common/boilerplate.polyfill';
2
1
  import type { NestExpressApplication } from '@nestjs/platform-express';
3
2
  export declare function bootstrapSetup(AppModule: any, SetupSwagger: any): Promise<NestExpressApplication<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>>;
@@ -17,7 +17,6 @@ const fs_1 = require("fs");
17
17
  const path_1 = require("path");
18
18
  const process = require("process");
19
19
  const mode_setup_1 = require("./mode.setup");
20
- require("../common/boilerplate.polyfill");
21
20
  function findValidRootPath() {
22
21
  const getAppRootPath = () => {
23
22
  if (require.main && require.main.filename) {
package/setup/index.d.ts CHANGED
@@ -2,4 +2,3 @@ export * from './bootstrap.setup';
2
2
  export * from './mode.setup';
3
3
  export * from './worker.decorator';
4
4
  export * from './schedule.decorator';
5
- export * from '../redis-lock';
package/setup/index.js CHANGED
@@ -18,4 +18,3 @@ __exportStar(require("./bootstrap.setup"), exports);
18
18
  __exportStar(require("./mode.setup"), exports);
19
19
  __exportStar(require("./worker.decorator"), exports);
20
20
  __exportStar(require("./schedule.decorator"), exports);
21
- __exportStar(require("../redis-lock"), exports);
@@ -125,6 +125,8 @@ if (services_1.ApiConfigService.toBoolean(process.env.CACHE_ENABLED)) {
125
125
  dataSource,
126
126
  memoryTtl: config.getNumber('CACHE_TTL'),
127
127
  memoryNamespace: config.getString('CACHE_NAMESPACE', 'default'),
128
+ enableCompression: config.getBoolean('CACHE_COMPRESSION_ENABLED', false),
129
+ compressionThreshold: config.getNumber('CACHE_COMPRESSION_THRESHOLD', 1024),
128
130
  };
129
131
  }),
130
132
  }));