@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.
- package/cache/cache-serialization.service.d.ts +4 -11
- package/cache/cache-serialization.service.js +29 -124
- package/cache/cache.constants.d.ts +2 -0
- package/cache/cache.constants.js +5 -0
- package/cache/cache.module.d.ts +2 -0
- package/cache/cache.module.js +49 -3
- package/cache/cache.service.d.ts +3 -1
- package/cache/cache.service.js +32 -4
- package/cache/examples/basic-usage.d.ts +58 -0
- package/cache/examples/basic-usage.js +379 -0
- package/cache/index.d.ts +2 -1
- package/cache/index.js +4 -1
- package/common/boilerplate.polyfill.d.ts +1 -7
- package/common/boilerplate.polyfill.js +1 -1
- package/common/dto/page-options.dto.d.ts +0 -3
- package/common/dto/page-options.dto.js +0 -12
- package/common/examples/paginate-and-map.example.d.ts +14 -0
- package/common/examples/paginate-and-map.example.js +158 -0
- package/decorators/examples/validation-decorators.example.d.ts +69 -0
- package/decorators/examples/validation-decorators.example.js +331 -0
- package/decorators/validator.decorators.d.ts +8 -1
- package/decorators/validator.decorators.js +115 -0
- package/i18n/en_US/validation.json +4 -1
- package/i18n/zh_CN/validation.json +4 -1
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/redis-lock/examples/lock-strategy.examples.d.ts +73 -0
- package/redis-lock/examples/lock-strategy.examples.js +387 -0
- package/redis-lock/index.d.ts +2 -2
- package/redis-lock/index.js +4 -1
- package/redis-lock/redis-lock.decorator.d.ts +4 -0
- package/redis-lock/redis-lock.decorator.js +43 -7
- package/redis-lock/redis-lock.service.d.ts +19 -0
- package/redis-lock/redis-lock.service.js +131 -6
- package/setup/bootstrap.setup.d.ts +0 -1
- package/setup/bootstrap.setup.js +0 -1
- package/setup/index.d.ts +0 -1
- package/setup/index.js +0 -1
- 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
|
|
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 (
|
|
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.
|
|
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.
|
|
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>>>;
|
package/setup/bootstrap.setup.js
CHANGED
|
@@ -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
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
|
}));
|