@nest-omni/core 4.1.3-1 → 4.1.3-11
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/audit/audit.module.d.ts +10 -0
- package/audit/audit.module.js +39 -1
- package/audit/controllers/audit.controller.d.ts +24 -0
- package/audit/controllers/audit.controller.js +24 -0
- package/audit/decorators/audit-controller.decorator.d.ts +9 -1
- package/audit/decorators/audit-controller.decorator.js +11 -2
- package/audit/decorators/audit-operation.decorator.d.ts +45 -0
- package/audit/decorators/audit-operation.decorator.js +49 -0
- package/audit/decorators/entity-audit.decorator.d.ts +76 -1
- package/audit/decorators/entity-audit.decorator.js +135 -3
- package/audit/decorators/index.d.ts +1 -0
- package/audit/decorators/index.js +1 -0
- package/audit/dto/audit-log-query.dto.d.ts +3 -0
- package/audit/dto/audit-log-query.dto.js +3 -0
- package/audit/dto/begin-transaction.dto.d.ts +3 -0
- package/audit/dto/begin-transaction.dto.js +3 -0
- package/audit/dto/compare-entities.dto.d.ts +3 -0
- package/audit/dto/compare-entities.dto.js +3 -0
- package/audit/dto/pre-check-restore.dto.d.ts +3 -0
- package/audit/dto/pre-check-restore.dto.js +3 -0
- package/audit/dto/restore-entity.dto.d.ts +3 -0
- package/audit/dto/restore-entity.dto.js +3 -0
- package/audit/entities/entity-audit-log.entity.d.ts +8 -0
- package/audit/entities/entity-audit-log.entity.js +33 -1
- package/audit/entities/entity-transaction.entity.d.ts +10 -0
- package/audit/entities/entity-transaction.entity.js +33 -1
- package/audit/entities/index.d.ts +2 -0
- package/audit/entities/index.js +2 -0
- package/audit/entities/manual-operation-log.entity.d.ts +4 -0
- package/audit/entities/manual-operation-log.entity.js +4 -0
- package/audit/entities/operation-template.entity.d.ts +4 -0
- package/audit/entities/operation-template.entity.js +4 -0
- package/audit/enums/audit.enums.d.ts +45 -5
- package/audit/enums/audit.enums.js +47 -4
- package/audit/index.d.ts +3 -1
- package/audit/index.js +30 -1
- package/audit/interceptors/audit.interceptor.d.ts +15 -0
- package/audit/interceptors/audit.interceptor.js +23 -1
- package/audit/interfaces/audit.interfaces.d.ts +182 -2
- package/audit/services/audit-context.service.d.ts +15 -0
- package/audit/services/audit-context.service.js +15 -0
- package/audit/services/audit-strategy.service.d.ts +6 -0
- package/audit/services/audit-strategy.service.js +13 -0
- package/audit/services/entity-audit.service.d.ts +129 -3
- package/audit/services/entity-audit.service.js +301 -6
- package/audit/services/index.d.ts +2 -0
- package/audit/services/index.js +2 -0
- package/audit/services/manual-audit-log.service.d.ts +124 -0
- package/audit/services/manual-audit-log.service.js +138 -0
- package/audit/services/multi-database.service.d.ts +12 -0
- package/audit/services/multi-database.service.js +12 -0
- package/audit/services/operation-description.service.d.ts +59 -0
- package/audit/services/operation-description.service.js +76 -2
- package/audit/services/transaction-audit.service.d.ts +30 -0
- package/audit/services/transaction-audit.service.js +47 -0
- package/audit/subscribers/entity-audit.subscriber.d.ts +15 -0
- package/audit/subscribers/entity-audit.subscriber.js +29 -1
- package/cache/cache-metrics.service.d.ts +67 -0
- package/cache/cache-metrics.service.js +68 -4
- package/cache/cache-serialization.service.d.ts +31 -0
- package/cache/cache-serialization.service.js +25 -0
- package/cache/cache.constants.d.ts +9 -0
- package/cache/cache.constants.js +9 -0
- package/cache/cache.health.d.ts +26 -0
- package/cache/cache.health.js +30 -0
- package/cache/cache.module.d.ts +86 -0
- package/cache/cache.module.js +71 -0
- package/cache/cache.service.d.ts +140 -0
- package/cache/cache.service.js +157 -0
- package/cache/cache.warmup.service.d.ts +39 -0
- package/cache/cache.warmup.service.js +32 -0
- package/cache/decorators/cache-evict.decorator.d.ts +47 -0
- package/cache/decorators/cache-evict.decorator.js +56 -0
- package/cache/decorators/cache-put.decorator.d.ts +34 -0
- package/cache/decorators/cache-put.decorator.js +39 -0
- package/cache/decorators/cacheable.decorator.d.ts +40 -0
- package/cache/decorators/cacheable.decorator.js +55 -0
- package/cache/dependencies/callback.dependency.d.ts +33 -0
- package/cache/dependencies/callback.dependency.js +39 -1
- package/cache/dependencies/chain.dependency.d.ts +28 -0
- package/cache/dependencies/chain.dependency.js +34 -0
- package/cache/dependencies/db.dependency.d.ts +45 -0
- package/cache/dependencies/db.dependency.js +48 -1
- package/cache/dependencies/file.dependency.d.ts +32 -0
- package/cache/dependencies/file.dependency.js +34 -0
- package/cache/dependencies/tag.dependency.d.ts +36 -0
- package/cache/dependencies/tag.dependency.js +36 -0
- package/cache/dependencies/time.dependency.d.ts +43 -0
- package/cache/dependencies/time.dependency.js +43 -0
- package/cache/examples/basic-usage.d.ts +15 -0
- package/cache/examples/basic-usage.js +62 -8
- package/cache/index.js +9 -0
- package/cache/interfaces/cache-dependency.interface.d.ts +53 -0
- package/cache/interfaces/cache-options.interface.d.ts +81 -0
- package/cache/interfaces/cache-options.interface.js +6 -0
- package/cache/interfaces/cache-provider.interface.d.ts +78 -0
- package/cache/providers/base-cache.provider.d.ts +14 -0
- package/cache/providers/base-cache.provider.js +16 -0
- package/cache/providers/cls-cache.provider.d.ts +20 -0
- package/cache/providers/cls-cache.provider.js +28 -0
- package/cache/providers/memory-cache.provider.d.ts +23 -0
- package/cache/providers/memory-cache.provider.js +26 -0
- package/cache/providers/redis-cache.provider.d.ts +26 -0
- package/cache/providers/redis-cache.provider.js +29 -0
- package/cache/utils/dependency-manager.util.d.ts +52 -0
- package/cache/utils/dependency-manager.util.js +59 -0
- package/cache/utils/key-generator.util.d.ts +42 -0
- package/cache/utils/key-generator.util.js +53 -1
- package/common/abstract.entity.d.ts +14 -0
- package/common/abstract.entity.js +14 -0
- package/common/boilerplate.polyfill.d.ts +142 -4
- package/common/boilerplate.polyfill.js +24 -100
- package/common/dto/dto-container.d.ts +16 -0
- package/common/dto/dto-container.js +20 -0
- package/common/dto/dto-decorators.d.ts +18 -0
- package/common/dto/dto-decorators.js +14 -0
- package/common/dto/dto-extensions.d.ts +11 -0
- package/common/dto/dto-extensions.js +9 -0
- package/common/dto/dto-service-accessor.d.ts +17 -0
- package/common/dto/dto-service-accessor.js +18 -0
- package/common/dto/dto-transformer.d.ts +12 -0
- package/common/dto/dto-transformer.js +9 -0
- package/common/dto/index.js +2 -0
- package/common/examples/paginate-and-map.example.d.ts +6 -0
- package/common/examples/paginate-and-map.example.js +26 -0
- package/common/utils.d.ts +15 -0
- package/common/utils.js +15 -0
- package/constants/language-code.js +1 -0
- package/decorators/field.decorators.js +8 -1
- package/decorators/property.decorators.js +1 -0
- package/decorators/public-route.decorator.js +1 -0
- package/decorators/transform.decorators.d.ts +27 -0
- package/decorators/transform.decorators.js +29 -0
- package/decorators/translate.decorator.js +1 -0
- package/decorators/user.decorator.js +1 -0
- package/decorators/validator.decorators.d.ts +8 -18
- package/decorators/validator.decorators.js +22 -190
- package/filters/constraint-errors.js +1 -0
- package/helpers/common.helper.d.ts +13 -0
- package/helpers/common.helper.js +13 -0
- package/http-client/config/http-client.config.d.ts +15 -0
- package/http-client/config/http-client.config.js +25 -9
- package/http-client/decorators/http-client.decorators.d.ts +63 -0
- package/http-client/decorators/http-client.decorators.js +71 -3
- package/http-client/entities/http-log.entity.d.ts +229 -0
- package/http-client/entities/http-log.entity.js +6 -1
- package/http-client/errors/http-client.errors.d.ts +57 -0
- package/http-client/errors/http-client.errors.js +58 -0
- package/http-client/examples/advanced-usage.example.d.ts +41 -0
- package/http-client/examples/advanced-usage.example.js +68 -24
- package/http-client/examples/auth-with-waiting-lock.example.d.ts +31 -0
- package/http-client/examples/auth-with-waiting-lock.example.js +52 -5
- package/http-client/examples/basic-usage.example.d.ts +60 -0
- package/http-client/examples/basic-usage.example.js +60 -0
- package/http-client/examples/multi-api-configuration.example.d.ts +60 -0
- package/http-client/examples/multi-api-configuration.example.js +76 -5
- package/http-client/http-client.module.d.ts +13 -0
- package/http-client/http-client.module.js +20 -5
- package/http-client/index.js +8 -0
- package/http-client/interfaces/api-client-config.interface.d.ts +125 -0
- package/http-client/interfaces/api-client-config.interface.js +3 -0
- package/http-client/interfaces/http-client-config.interface.d.ts +60 -0
- package/http-client/services/api-client-registry.service.d.ts +57 -0
- package/http-client/services/api-client-registry.service.js +84 -1
- package/http-client/services/cache.service.d.ts +52 -0
- package/http-client/services/cache.service.js +72 -3
- package/http-client/services/circuit-breaker.service.d.ts +46 -0
- package/http-client/services/circuit-breaker.service.js +52 -0
- package/http-client/services/http-client.service.d.ts +67 -0
- package/http-client/services/http-client.service.js +105 -4
- package/http-client/services/http-log-query.service.d.ts +83 -0
- package/http-client/services/http-log-query.service.js +122 -1
- package/http-client/services/http-replay.service.d.ts +101 -0
- package/http-client/services/http-replay.service.js +86 -0
- package/http-client/services/log-cleanup.service.d.ts +63 -0
- package/http-client/services/log-cleanup.service.js +54 -2
- package/http-client/services/logging.service.d.ts +40 -0
- package/http-client/services/logging.service.js +53 -0
- package/http-client/utils/call-stack-extractor.util.d.ts +37 -0
- package/http-client/utils/call-stack-extractor.util.js +48 -0
- package/http-client/utils/context-extractor.util.d.ts +49 -0
- package/http-client/utils/context-extractor.util.js +52 -0
- package/http-client/utils/curl-generator.util.d.ts +21 -0
- package/http-client/utils/curl-generator.util.js +44 -3
- package/http-client/utils/request-id.util.d.ts +18 -0
- package/http-client/utils/request-id.util.js +20 -0
- package/http-client/utils/retry-recorder.util.d.ts +42 -0
- package/http-client/utils/retry-recorder.util.js +44 -0
- package/i18n/en_US/validation.json +2 -1
- package/i18n/zh_CN/validation.json +2 -1
- package/index.js +8 -0
- package/interceptors/translation-interceptor.service.js +5 -0
- package/package.json +1 -1
- package/providers/context.provider.js +2 -0
- package/providers/generator.provider.d.ts +4 -0
- package/providers/generator.provider.js +4 -0
- package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
- package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
- package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
- package/redis-lock/examples/lock-strategy.examples.js +130 -15
- package/redis-lock/index.d.ts +2 -0
- package/redis-lock/index.js +8 -1
- package/redis-lock/lock-heartbeat.service.d.ts +78 -0
- package/redis-lock/lock-heartbeat.service.js +222 -0
- package/redis-lock/redis-lock.decorator.d.ts +101 -0
- package/redis-lock/redis-lock.decorator.js +120 -0
- package/redis-lock/redis-lock.module.d.ts +66 -0
- package/redis-lock/redis-lock.module.js +175 -70
- package/redis-lock/redis-lock.service.d.ts +278 -0
- package/redis-lock/redis-lock.service.js +282 -12
- package/setup/bootstrap.setup.js +20 -0
- package/setup/mode.setup.d.ts +44 -0
- package/setup/mode.setup.js +44 -0
- package/setup/schedule.decorator.d.ts +227 -0
- package/setup/schedule.decorator.js +235 -12
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +88 -0
- package/shared/serviceRegistryModule.js +27 -14
- package/shared/services/api-config.service.d.ts +3 -0
- package/shared/services/api-config.service.js +20 -9
- package/validator-json/decorators.d.ts +17 -0
- package/validator-json/decorators.js +17 -2
- package/validator-json/default.d.ts +6 -0
- package/validator-json/default.js +30 -2
- package/validator-json/defaultConverters.js +1 -0
- package/validator-json/options.d.ts +23 -0
- package/validators/common-validators.d.ts +143 -0
- package/validators/common-validators.js +249 -0
- package/validators/custom-validate.examples.d.ts +96 -0
- package/validators/custom-validate.examples.js +400 -0
- package/validators/custom-validate.validator.d.ts +134 -0
- package/validators/custom-validate.validator.js +214 -0
- package/validators/index.d.ts +2 -0
- package/validators/index.js +2 -0
- package/validators/is-exists.validator.d.ts +18 -4
- package/validators/is-exists.validator.js +67 -6
- package/validators/is-unique.validator.d.ts +32 -5
- package/validators/is-unique.validator.js +99 -17
- package/validators/skip-empty.validator.d.ts +5 -0
- package/validators/skip-empty.validator.js +5 -0
- package/vault/interfaces/vault-options.interface.d.ts +9 -0
- package/vault/vault-config.loader.d.ts +30 -0
- package/vault/vault-config.loader.js +48 -1
- package/vault/vault-config.service.d.ts +53 -0
- package/vault/vault-config.service.js +57 -0
- package/vault/vault.module.d.ts +4 -0
- package/vault/vault.module.js +4 -0
- package/decorators/examples/validation-decorators.example.d.ts +0 -69
- package/decorators/examples/validation-decorators.example.js +0 -331
|
@@ -21,39 +21,96 @@ var RedisLockService_1;
|
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
22
|
exports.RedisLockService = exports.LockStrategy = void 0;
|
|
23
23
|
const common_1 = require("@nestjs/common");
|
|
24
|
+
/**
|
|
25
|
+
* Lock acquisition strategy
|
|
26
|
+
*/
|
|
24
27
|
var LockStrategy;
|
|
25
28
|
(function (LockStrategy) {
|
|
29
|
+
/**
|
|
30
|
+
* Skip execution if lock cannot be acquired immediately
|
|
31
|
+
* This is the default behavior for backward compatibility
|
|
32
|
+
*/
|
|
26
33
|
LockStrategy["SKIP"] = "SKIP";
|
|
34
|
+
/**
|
|
35
|
+
* Throw an error if lock cannot be acquired
|
|
36
|
+
* Useful for critical operations that must have exclusive access
|
|
37
|
+
*/
|
|
27
38
|
LockStrategy["THROW"] = "THROW";
|
|
39
|
+
/**
|
|
40
|
+
* Wait/block until the lock can be acquired
|
|
41
|
+
* Will retry indefinitely with the specified retry delay
|
|
42
|
+
*/
|
|
28
43
|
LockStrategy["WAIT"] = "WAIT";
|
|
29
44
|
})(LockStrategy || (exports.LockStrategy = LockStrategy = {}));
|
|
45
|
+
/**
|
|
46
|
+
* Redis-based distributed lock service
|
|
47
|
+
*
|
|
48
|
+
* Provides thread-safe, distributed locking mechanism using Redis.
|
|
49
|
+
* Supports automatic lock expiration, retries, proper lock release,
|
|
50
|
+
* and automatic lock extension.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* constructor(private lockService: RedisLockService) {}
|
|
55
|
+
*
|
|
56
|
+
* async processTask() {
|
|
57
|
+
* const result = await this.lockService.acquireLock('task:process', { ttl: 60000 });
|
|
58
|
+
*
|
|
59
|
+
* if (result.acquired) {
|
|
60
|
+
* try {
|
|
61
|
+
* // Do work
|
|
62
|
+
* } finally {
|
|
63
|
+
* await this.lockService.releaseLock('task:process', result.lockValue);
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
30
69
|
let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
31
70
|
constructor() {
|
|
32
71
|
this.logger = new common_1.Logger(RedisLockService_1.name);
|
|
33
72
|
this.redis = null;
|
|
34
73
|
this.defaultOptions = {
|
|
35
|
-
ttl: 300000,
|
|
36
|
-
retryCount: 0
|
|
37
|
-
retryDelay: 100
|
|
74
|
+
ttl: 300000, // 5 minutes
|
|
75
|
+
retryCount: 3, // Increased from 0 to provide reasonable retry attempts
|
|
76
|
+
retryDelay: 500, // Increased from 100 to reduce retry frequency
|
|
38
77
|
keyPrefix: 'lock',
|
|
39
78
|
throwOnFailure: false,
|
|
40
79
|
strategy: LockStrategy.SKIP,
|
|
41
80
|
waitTimeout: undefined,
|
|
42
|
-
autoExtend: 0,
|
|
81
|
+
autoExtend: 0, // No auto-extension by default
|
|
82
|
+
useExponentialBackoff: true, // Enable exponential backoff by default
|
|
83
|
+
maxRetryDelay: 30000, // Maximum retry delay of 30 seconds
|
|
84
|
+
retryJitter: 100, // Add random jitter to avoid synchronized retries
|
|
43
85
|
};
|
|
86
|
+
// Set global instance when created
|
|
44
87
|
if (!RedisLockService_1.globalInstance) {
|
|
45
88
|
RedisLockService_1.globalInstance = this;
|
|
46
89
|
}
|
|
90
|
+
// Initialize instance ID
|
|
91
|
+
this.instanceId = this.getInstanceId();
|
|
47
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the global singleton instance
|
|
95
|
+
* This allows decorators to access the service without dependency injection
|
|
96
|
+
*/
|
|
48
97
|
static getGlobalInstance() {
|
|
49
98
|
return RedisLockService_1.globalInstance;
|
|
50
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Get or create the global singleton instance
|
|
102
|
+
* If no instance exists, it will create one
|
|
103
|
+
*/
|
|
51
104
|
static getOrCreateGlobalInstance() {
|
|
52
105
|
if (!RedisLockService_1.globalInstance) {
|
|
53
106
|
RedisLockService_1.globalInstance = new RedisLockService_1();
|
|
54
107
|
}
|
|
55
108
|
return RedisLockService_1.globalInstance;
|
|
56
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Set the global singleton instance
|
|
112
|
+
* Useful for testing or manual setup
|
|
113
|
+
*/
|
|
57
114
|
static setGlobalInstance(instance) {
|
|
58
115
|
RedisLockService_1.globalInstance = instance;
|
|
59
116
|
}
|
|
@@ -69,37 +126,65 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
69
126
|
}
|
|
70
127
|
onModuleDestroy() {
|
|
71
128
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
// We don't manage the Redis connection lifecycle anymore
|
|
130
|
+
// The injected Redis client is managed by the Redis module
|
|
72
131
|
this.logger.log('RedisLockService destroyed');
|
|
73
132
|
});
|
|
74
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Set Redis client (required for dependency injection)
|
|
136
|
+
* This service requires an external Redis client to function
|
|
137
|
+
*/
|
|
75
138
|
setRedisClient(redis) {
|
|
76
139
|
this.redis = redis;
|
|
77
140
|
this.logger.log('Redis client set for RedisLockService');
|
|
78
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Set default TTL for locks
|
|
144
|
+
*/
|
|
79
145
|
setDefaultTtl(ttl) {
|
|
80
146
|
this.defaultOptions.ttl = ttl;
|
|
81
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Set default key prefix for locks
|
|
150
|
+
*/
|
|
82
151
|
setDefaultKeyPrefix(prefix) {
|
|
83
152
|
this.defaultOptions.keyPrefix = prefix;
|
|
84
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Set default retry count for lock acquisition
|
|
156
|
+
*/
|
|
85
157
|
setDefaultRetryCount(count) {
|
|
86
158
|
this.defaultOptions.retryCount = count;
|
|
87
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Set default retry delay for lock acquisition
|
|
162
|
+
*/
|
|
88
163
|
setDefaultRetryDelay(delay) {
|
|
89
164
|
this.defaultOptions.retryDelay = delay;
|
|
90
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Acquire a distributed lock
|
|
168
|
+
*
|
|
169
|
+
* @param key - Lock key (will be prefixed with 'lock:')
|
|
170
|
+
* @param options - Lock options
|
|
171
|
+
* @returns Lock acquisition result
|
|
172
|
+
*/
|
|
91
173
|
acquireLock(key_1) {
|
|
92
174
|
return __awaiter(this, arguments, void 0, function* (key, options = {}) {
|
|
175
|
+
var _a, _b, _c, _d, _e;
|
|
93
176
|
const redis = yield this.getRedis();
|
|
94
177
|
const opts = Object.assign(Object.assign({}, this.defaultOptions), options);
|
|
178
|
+
// Handle backward compatibility: if throwOnFailure is true, use THROW strategy
|
|
95
179
|
if (opts.throwOnFailure && !options.strategy) {
|
|
96
180
|
opts.strategy = LockStrategy.THROW;
|
|
97
181
|
}
|
|
98
182
|
const lockKey = this.buildLockKey(key, opts.keyPrefix);
|
|
99
183
|
const lockValue = this.generateLockValue();
|
|
184
|
+
// Determine max attempts based on strategy
|
|
100
185
|
let maxAttempts;
|
|
101
186
|
if (opts.strategy === LockStrategy.WAIT) {
|
|
102
|
-
maxAttempts = Number.MAX_SAFE_INTEGER;
|
|
187
|
+
maxAttempts = Number.MAX_SAFE_INTEGER; // Infinite retries for WAIT strategy
|
|
103
188
|
}
|
|
104
189
|
else {
|
|
105
190
|
maxAttempts = opts.retryCount + 1;
|
|
@@ -107,6 +192,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
107
192
|
let attempts = 0;
|
|
108
193
|
const startTime = Date.now();
|
|
109
194
|
while (attempts < maxAttempts) {
|
|
195
|
+
// Check timeout for WAIT strategy
|
|
110
196
|
if (opts.strategy === LockStrategy.WAIT && opts.waitTimeout) {
|
|
111
197
|
const elapsed = Date.now() - startTime;
|
|
112
198
|
if (elapsed >= opts.waitTimeout) {
|
|
@@ -116,9 +202,11 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
116
202
|
}
|
|
117
203
|
}
|
|
118
204
|
try {
|
|
205
|
+
// Use SET with NX (Not eXists) and PX (expiration in milliseconds)
|
|
119
206
|
const result = yield redis.set(lockKey, lockValue, 'PX', opts.ttl, 'NX');
|
|
120
207
|
if (result === 'OK') {
|
|
121
208
|
this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms, attempts: ${attempts + 1})`);
|
|
209
|
+
// Set up auto-extension if enabled
|
|
122
210
|
let autoExtendTimer;
|
|
123
211
|
if (opts.autoExtend && opts.autoExtend > 0) {
|
|
124
212
|
autoExtendTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -132,7 +220,9 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
132
220
|
}
|
|
133
221
|
return { acquired: true, lockValue, autoExtendTimer };
|
|
134
222
|
}
|
|
223
|
+
// Lock acquisition failed
|
|
135
224
|
attempts++;
|
|
225
|
+
// For WAIT strategy, log less frequently to avoid spam
|
|
136
226
|
if (opts.strategy === LockStrategy.WAIT) {
|
|
137
227
|
if (attempts === 1 || attempts % 10 === 0) {
|
|
138
228
|
this.logger.debug(`Waiting for lock ${lockKey}... (attempt ${attempts})`);
|
|
@@ -141,19 +231,47 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
141
231
|
else if (attempts < maxAttempts) {
|
|
142
232
|
this.logger.debug(`Lock acquisition failed for ${lockKey}, retrying... (${attempts}/${opts.retryCount})`);
|
|
143
233
|
}
|
|
234
|
+
// Wait before next attempt (except for last attempt)
|
|
144
235
|
if (attempts < maxAttempts) {
|
|
145
|
-
|
|
236
|
+
// Add random jitter to avoid synchronized retries
|
|
237
|
+
const jitter = opts.retryJitter ? Math.random() * opts.retryJitter : 0;
|
|
238
|
+
const totalDelay = opts.retryDelay + jitter;
|
|
239
|
+
yield this.sleep(totalDelay);
|
|
146
240
|
}
|
|
147
241
|
}
|
|
148
242
|
catch (error) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
243
|
+
// Enhanced error classification and handling
|
|
244
|
+
if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('ECONNREFUSED')) ||
|
|
245
|
+
((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes('ECONNRESET')) ||
|
|
246
|
+
error.code === 'ECONNREFUSED') {
|
|
247
|
+
// Connection error, will retry - log at debug level
|
|
248
|
+
this.logger.debug(`Redis connection error, will retry: ${error.message}`);
|
|
249
|
+
}
|
|
250
|
+
else if (((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes('READONLY')) ||
|
|
251
|
+
((_d = error.message) === null || _d === void 0 ? void 0 : _d.includes('LOADING')) ||
|
|
252
|
+
((_e = error.message) === null || _e === void 0 ? void 0 : _e.includes('MASTERDOWN'))) {
|
|
253
|
+
// Redis server error, log at warn level
|
|
254
|
+
this.logger.warn(`Redis server error: ${error.message}`);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
// Other errors, log at error level
|
|
258
|
+
const errorMessage = `Error acquiring lock for ${lockKey}: ${error.message}`;
|
|
259
|
+
this.logger.error(errorMessage, error.stack);
|
|
260
|
+
if (opts.strategy === LockStrategy.THROW) {
|
|
261
|
+
throw new Error(errorMessage);
|
|
262
|
+
}
|
|
263
|
+
return { acquired: false, error: errorMessage };
|
|
264
|
+
}
|
|
265
|
+
// For retryable errors, continue with retry logic
|
|
266
|
+
attempts++;
|
|
267
|
+
if (attempts < maxAttempts) {
|
|
268
|
+
const jitter = opts.retryJitter ? Math.random() * opts.retryJitter : 0;
|
|
269
|
+
const totalDelay = opts.retryDelay + jitter;
|
|
270
|
+
yield this.sleep(totalDelay);
|
|
153
271
|
}
|
|
154
|
-
return { acquired: false, error: errorMessage };
|
|
155
272
|
}
|
|
156
273
|
}
|
|
274
|
+
// Max attempts reached
|
|
157
275
|
const failureMessage = `Failed to acquire lock for ${lockKey} after ${attempts} attempts`;
|
|
158
276
|
this.logger.warn(failureMessage);
|
|
159
277
|
if (opts.strategy === LockStrategy.THROW) {
|
|
@@ -162,11 +280,23 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
162
280
|
return { acquired: false, error: failureMessage };
|
|
163
281
|
});
|
|
164
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Release a distributed lock
|
|
285
|
+
*
|
|
286
|
+
* Uses Lua script to ensure atomic check-and-delete operation
|
|
287
|
+
* Only releases the lock if the value matches (prevents releasing someone else's lock)
|
|
288
|
+
*
|
|
289
|
+
* @param key - Lock key
|
|
290
|
+
* @param lockValue - Lock value obtained during acquisition
|
|
291
|
+
* @param keyPrefix - Key prefix (must match acquisition)
|
|
292
|
+
* @returns True if lock was released, false otherwise
|
|
293
|
+
*/
|
|
165
294
|
releaseLock(key_1, lockValue_1) {
|
|
166
295
|
return __awaiter(this, arguments, void 0, function* (key, lockValue, keyPrefix = 'lock') {
|
|
167
296
|
const redis = yield this.getRedis();
|
|
168
297
|
const lockKey = this.buildLockKey(key, keyPrefix);
|
|
169
298
|
try {
|
|
299
|
+
// Lua script to atomically check and delete the lock
|
|
170
300
|
const script = `
|
|
171
301
|
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
172
302
|
return redis.call("del", KEYS[1])
|
|
@@ -190,11 +320,21 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
190
320
|
}
|
|
191
321
|
});
|
|
192
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Extend the expiration time of an existing lock
|
|
325
|
+
*
|
|
326
|
+
* @param key - Lock key
|
|
327
|
+
* @param lockValue - Lock value obtained during acquisition
|
|
328
|
+
* @param ttl - New TTL in milliseconds
|
|
329
|
+
* @param keyPrefix - Key prefix (must match acquisition)
|
|
330
|
+
* @returns True if lock was extended, false otherwise
|
|
331
|
+
*/
|
|
193
332
|
extendLock(key_1, lockValue_1, ttl_1) {
|
|
194
333
|
return __awaiter(this, arguments, void 0, function* (key, lockValue, ttl, keyPrefix = 'lock') {
|
|
195
334
|
const redis = yield this.getRedis();
|
|
196
335
|
const lockKey = this.buildLockKey(key, keyPrefix);
|
|
197
336
|
try {
|
|
337
|
+
// Lua script to atomically check value and extend TTL
|
|
198
338
|
const script = `
|
|
199
339
|
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
200
340
|
return redis.call("pexpire", KEYS[1], ARGV[2])
|
|
@@ -218,6 +358,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
218
358
|
}
|
|
219
359
|
});
|
|
220
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Check if a lock exists
|
|
363
|
+
*
|
|
364
|
+
* @param key - Lock key
|
|
365
|
+
* @param keyPrefix - Key prefix
|
|
366
|
+
* @returns True if lock exists, false otherwise
|
|
367
|
+
*/
|
|
221
368
|
isLocked(key_1) {
|
|
222
369
|
return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
|
|
223
370
|
const redis = yield this.getRedis();
|
|
@@ -232,6 +379,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
232
379
|
}
|
|
233
380
|
});
|
|
234
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Execute a function with automatic lock acquisition and release
|
|
384
|
+
*
|
|
385
|
+
* @param key - Lock key
|
|
386
|
+
* @param fn - Function to execute while holding the lock
|
|
387
|
+
* @param options - Lock options
|
|
388
|
+
* @returns Result of the function execution, or null if lock couldn't be acquired
|
|
389
|
+
*/
|
|
235
390
|
withLock(key_1, fn_1) {
|
|
236
391
|
return __awaiter(this, arguments, void 0, function* (key, fn, options = {}) {
|
|
237
392
|
const lockResult = yield this.acquireLock(key, options);
|
|
@@ -247,6 +402,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
247
402
|
throw error;
|
|
248
403
|
}
|
|
249
404
|
finally {
|
|
405
|
+
// Clear auto-extension timer if it exists
|
|
250
406
|
if (lockResult.autoExtendTimer) {
|
|
251
407
|
clearInterval(lockResult.autoExtendTimer);
|
|
252
408
|
}
|
|
@@ -254,6 +410,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
254
410
|
}
|
|
255
411
|
});
|
|
256
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Get lock information from Redis
|
|
415
|
+
*
|
|
416
|
+
* @param key - Lock key
|
|
417
|
+
* @param keyPrefix - Key prefix
|
|
418
|
+
* @returns Lock information including TTL and value
|
|
419
|
+
*/
|
|
257
420
|
getLockInfo(key_1) {
|
|
258
421
|
return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
|
|
259
422
|
const redis = yield this.getRedis();
|
|
@@ -274,6 +437,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
274
437
|
}
|
|
275
438
|
});
|
|
276
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Force release a lock (use with caution)
|
|
442
|
+
*
|
|
443
|
+
* @param key - Lock key
|
|
444
|
+
* @param keyPrefix - Key prefix
|
|
445
|
+
* @returns True if lock was released, false otherwise
|
|
446
|
+
*/
|
|
277
447
|
forceRelease(key_1) {
|
|
278
448
|
return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
|
|
279
449
|
const redis = yield this.getRedis();
|
|
@@ -295,6 +465,25 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
295
465
|
}
|
|
296
466
|
});
|
|
297
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Clean up locks by pattern
|
|
470
|
+
* Useful for cleaning up locks after process restart or for specific services
|
|
471
|
+
*
|
|
472
|
+
* WARNING: Use with caution in production! This will forcefully delete locks.
|
|
473
|
+
*
|
|
474
|
+
* @param pattern - Lock pattern (e.g., 'MyService:*' or '*:migration:*')
|
|
475
|
+
* @param keyPrefix - Key prefix (default: 'lock')
|
|
476
|
+
* @returns Number of locks deleted
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```typescript
|
|
480
|
+
* // Clean up all locks for MyService
|
|
481
|
+
* await lockService.cleanupLocksByPattern('MyService:*');
|
|
482
|
+
*
|
|
483
|
+
* // Clean up all migration locks
|
|
484
|
+
* await lockService.cleanupLocksByPattern('*:migration:*');
|
|
485
|
+
* ```
|
|
486
|
+
*/
|
|
298
487
|
cleanupLocksByPattern(pattern_1) {
|
|
299
488
|
return __awaiter(this, arguments, void 0, function* (pattern, keyPrefix = 'lock') {
|
|
300
489
|
const redis = yield this.getRedis();
|
|
@@ -315,6 +504,28 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
315
504
|
}
|
|
316
505
|
});
|
|
317
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Clean up locks on startup
|
|
509
|
+
* This method is useful for cleaning up stale locks from previous process instances
|
|
510
|
+
*
|
|
511
|
+
* WARNING: Only use this if you're sure the locks are from previous process instances!
|
|
512
|
+
*
|
|
513
|
+
* @param patterns - Array of lock patterns to clean up
|
|
514
|
+
* @param keyPrefix - Key prefix (default: 'lock')
|
|
515
|
+
* @returns Total number of locks deleted
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```typescript
|
|
519
|
+
* // In your module's onModuleInit
|
|
520
|
+
* async onModuleInit() {
|
|
521
|
+
* // Clean up locks from this service that might be left from previous restart
|
|
522
|
+
* await this.lockService.cleanupOnStartup([
|
|
523
|
+
* 'MyService:*',
|
|
524
|
+
* 'AnotherService:*'
|
|
525
|
+
* ]);
|
|
526
|
+
* }
|
|
527
|
+
* ```
|
|
528
|
+
*/
|
|
318
529
|
cleanupOnStartup(patterns_1) {
|
|
319
530
|
return __awaiter(this, arguments, void 0, function* (patterns, keyPrefix = 'lock') {
|
|
320
531
|
this.logger.log(`Starting lock cleanup for ${patterns.length} pattern(s) on startup...`);
|
|
@@ -327,10 +538,17 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
327
538
|
return totalDeleted;
|
|
328
539
|
});
|
|
329
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* Health check for Redis connection
|
|
543
|
+
* Returns information about Redis connectivity and lock service status
|
|
544
|
+
*
|
|
545
|
+
* @returns Health check result
|
|
546
|
+
*/
|
|
330
547
|
healthCheck() {
|
|
331
548
|
return __awaiter(this, void 0, void 0, function* () {
|
|
332
549
|
try {
|
|
333
550
|
const redis = yield this.getRedis();
|
|
551
|
+
// Try to ping Redis
|
|
334
552
|
const pong = yield redis.ping();
|
|
335
553
|
if (pong === 'PONG') {
|
|
336
554
|
return {
|
|
@@ -356,6 +574,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
356
574
|
}
|
|
357
575
|
});
|
|
358
576
|
}
|
|
577
|
+
/**
|
|
578
|
+
* Get all active locks with optional pattern filtering
|
|
579
|
+
* Useful for monitoring and debugging
|
|
580
|
+
*
|
|
581
|
+
* @param pattern - Optional pattern to filter locks (e.g., 'MyService:*')
|
|
582
|
+
* @param keyPrefix - Key prefix (default: 'lock')
|
|
583
|
+
* @returns Array of active lock information
|
|
584
|
+
*/
|
|
359
585
|
getActiveLocks() {
|
|
360
586
|
return __awaiter(this, arguments, void 0, function* (pattern = '*', keyPrefix = 'lock') {
|
|
361
587
|
const redis = yield this.getRedis();
|
|
@@ -370,6 +596,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
370
596
|
redis.get(key),
|
|
371
597
|
redis.pttl(key),
|
|
372
598
|
]);
|
|
599
|
+
// Remove the key prefix for cleaner output
|
|
373
600
|
const cleanKey = key.startsWith(`${keyPrefix}:`)
|
|
374
601
|
? key.substring(`${keyPrefix}:`.length)
|
|
375
602
|
: key;
|
|
@@ -387,6 +614,10 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
387
614
|
}
|
|
388
615
|
});
|
|
389
616
|
}
|
|
617
|
+
/**
|
|
618
|
+
* Get Redis connection
|
|
619
|
+
* Requires external Redis client to be set
|
|
620
|
+
*/
|
|
390
621
|
getRedis() {
|
|
391
622
|
return __awaiter(this, void 0, void 0, function* () {
|
|
392
623
|
if (!this.redis) {
|
|
@@ -395,12 +626,51 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
395
626
|
return this.redis;
|
|
396
627
|
});
|
|
397
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* Generate a unique lock value
|
|
631
|
+
* Format: instanceId:timestamp:random:pid
|
|
632
|
+
*
|
|
633
|
+
* @returns Unique lock identifier
|
|
634
|
+
*/
|
|
398
635
|
generateLockValue() {
|
|
399
|
-
|
|
636
|
+
const timestamp = Date.now();
|
|
637
|
+
const random = Math.random().toString(36).substring(2, 15);
|
|
638
|
+
const pid = process.pid;
|
|
639
|
+
return `${this.instanceId}:${timestamp}:${random}:${pid}`;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Get instance identifier
|
|
643
|
+
* Used to distinguish different process instances in distributed environments
|
|
644
|
+
*
|
|
645
|
+
* @returns Instance identifier
|
|
646
|
+
*/
|
|
647
|
+
getInstanceId() {
|
|
648
|
+
// 1. Kubernetes Pod name
|
|
649
|
+
if (process.env.HOSTNAME) {
|
|
650
|
+
return process.env.HOSTNAME;
|
|
651
|
+
}
|
|
652
|
+
// 2. Custom instance ID
|
|
653
|
+
if (process.env.INSTANCE_ID) {
|
|
654
|
+
return process.env.INSTANCE_ID;
|
|
655
|
+
}
|
|
656
|
+
// 3. Generate unique ID
|
|
657
|
+
return `instance-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
400
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* Build the full Redis key for a lock
|
|
661
|
+
*
|
|
662
|
+
* @param key - Lock key
|
|
663
|
+
* @param prefix - Key prefix
|
|
664
|
+
* @returns Full Redis key
|
|
665
|
+
*/
|
|
401
666
|
buildLockKey(key, prefix = 'lock') {
|
|
402
667
|
return `${prefix}:${key}`;
|
|
403
668
|
}
|
|
669
|
+
/**
|
|
670
|
+
* Sleep for a specified duration
|
|
671
|
+
*
|
|
672
|
+
* @param ms - Milliseconds to sleep
|
|
673
|
+
*/
|
|
404
674
|
sleep(ms) {
|
|
405
675
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
406
676
|
}
|
package/setup/bootstrap.setup.js
CHANGED
|
@@ -19,12 +19,15 @@ const process = require("process");
|
|
|
19
19
|
const mode_setup_1 = require("./mode.setup");
|
|
20
20
|
function findValidRootPath() {
|
|
21
21
|
const getAppRootPath = () => {
|
|
22
|
+
// 优先使用 require.main.filename(应用入口文件)
|
|
22
23
|
if (require.main && require.main.filename) {
|
|
23
24
|
return (0, path_1.dirname)(require.main.filename);
|
|
24
25
|
}
|
|
26
|
+
// fallback 到 process.argv[1]
|
|
25
27
|
if (process.argv[1]) {
|
|
26
28
|
return (0, path_1.dirname)(process.argv[1]);
|
|
27
29
|
}
|
|
30
|
+
// 最后 fallback 到当前工作目录
|
|
28
31
|
return process.cwd();
|
|
29
32
|
};
|
|
30
33
|
const possibleRootPaths = [getAppRootPath(), process.cwd(), __dirname];
|
|
@@ -56,6 +59,8 @@ function findValidRootPath() {
|
|
|
56
59
|
throw new Error(`No valid .env file: ${envFilePath}`);
|
|
57
60
|
}
|
|
58
61
|
const { envFilePath, rootPath, baseEnvFilePath } = findValidRootPath();
|
|
62
|
+
// 配置加载顺序: base.env < 环境.env < Vault
|
|
63
|
+
// 1. 先加载本地配置文件 (base.env 和 环境.env)
|
|
59
64
|
dotenv.config({ path: [envFilePath, baseEnvFilePath] });
|
|
60
65
|
process.env.ROOT_PATH = rootPath;
|
|
61
66
|
process.env.ENV_FILE_PATH = envFilePath;
|
|
@@ -121,34 +126,47 @@ const vault_1 = require("../vault");
|
|
|
121
126
|
const dto_1 = require("../common/dto");
|
|
122
127
|
function bootstrapSetup(AppModule, SetupSwagger) {
|
|
123
128
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
// 2. 加载 Vault 配置(会覆盖 .env 中的配置)
|
|
124
130
|
yield vault_1.VaultConfigLoader.loadVaultConfig();
|
|
131
|
+
// 获取应用模式
|
|
125
132
|
const shouldStartHttp = (0, mode_setup_1.shouldStartHttpServer)();
|
|
133
|
+
// 创建应用实例
|
|
126
134
|
const app = yield core_1.NestFactory.create(AppModule, {
|
|
127
135
|
bufferLogs: true,
|
|
128
136
|
autoFlushLogs: true,
|
|
129
137
|
});
|
|
138
|
+
// 设置容器 - 类似class-validator的useContainer
|
|
130
139
|
const appModuleRef = app.select(AppModule);
|
|
131
140
|
(0, class_validator_1.useContainer)(appModuleRef, { fallbackOnErrors: true });
|
|
141
|
+
// 初始化DTO容器
|
|
132
142
|
dto_1.DtoContainer.useContainer(appModuleRef);
|
|
143
|
+
// 获取核心服务
|
|
133
144
|
const configService = app.select(__1.ServiceRegistryModule).get(__1.ApiConfigService);
|
|
134
145
|
const logger = app.get(nestjs_pino_1.Logger);
|
|
135
146
|
app.useLogger(logger);
|
|
136
147
|
app.flushLogs();
|
|
148
|
+
// 记录应用模式
|
|
137
149
|
logger.log(`Application Mode: ${(0, mode_setup_1.getModeDescription)()}`);
|
|
138
150
|
logger.log(`Environment: ${process.env.NODE_ENV || 'unknown'}`);
|
|
139
151
|
app.enableShutdownHooks();
|
|
152
|
+
// 基础配置
|
|
140
153
|
app.enableVersioning();
|
|
141
154
|
app.enable('trust proxy');
|
|
142
155
|
app.set('query parser', 'extended');
|
|
156
|
+
// 中间件配置
|
|
143
157
|
app.use(bodyParse.urlencoded({
|
|
144
158
|
extended: true,
|
|
145
159
|
parameterLimit: 1000,
|
|
146
160
|
}), bodyParse.json({ limit: '50mb' }), new nestjs_cls_1.ClsMiddleware({
|
|
147
161
|
saveReq: true,
|
|
162
|
+
// 启用请求保存,解决CLS相关的上下文问题
|
|
148
163
|
}).use, (0, __1.RequestIdMiddleware)(), (0, __1.PowerByMiddleware)(), (0, __1.OmniAuthMiddleware)(), compression());
|
|
164
|
+
// 全局过滤器
|
|
149
165
|
const reflector = app.get(core_1.Reflector);
|
|
150
166
|
app.useGlobalFilters(new setup_1.SentryGlobalFilter(), new __1.HttpExceptionFilter(), new __1.QueryFailedFilter(reflector));
|
|
167
|
+
// 全局拦截器
|
|
151
168
|
app.useGlobalInterceptors(new __1.LanguageInterceptor(), new __1.TranslationInterceptor(), new nestjs_pino_1.LoggerErrorInterceptor());
|
|
169
|
+
// 全局管道
|
|
152
170
|
app.useGlobalPipes(new nestjs_i18n_1.I18nValidationPipe({
|
|
153
171
|
whitelist: true,
|
|
154
172
|
errorHttpStatusCode: common_1.HttpStatus.UNPROCESSABLE_ENTITY,
|
|
@@ -156,6 +174,7 @@ function bootstrapSetup(AppModule, SetupSwagger) {
|
|
|
156
174
|
stopAtFirstError: true,
|
|
157
175
|
validationError: { target: false, value: false },
|
|
158
176
|
}));
|
|
177
|
+
// 可选功能模块 - 仅在 HTTP 或 Hybrid 模式下启用
|
|
159
178
|
if (shouldStartHttp) {
|
|
160
179
|
if (configService.documentationEnabled && SetupSwagger) {
|
|
161
180
|
SetupSwagger(app, configService.documentationPath);
|
|
@@ -181,6 +200,7 @@ function bootstrapSetup(AppModule, SetupSwagger) {
|
|
|
181
200
|
else {
|
|
182
201
|
logger.log('Running in Worker-only mode - HTTP server not started');
|
|
183
202
|
logger.log('Application is ready to process background tasks');
|
|
203
|
+
// 在 Worker 模式下,应用会持续运行但不监听 HTTP 请求
|
|
184
204
|
yield app.init();
|
|
185
205
|
}
|
|
186
206
|
return app;
|
package/setup/mode.setup.d.ts
CHANGED
|
@@ -1,12 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Mode Detection and Management System
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for detecting and managing different application modes:
|
|
5
|
+
* - HTTP: Only HTTP server (no workers/schedulers)
|
|
6
|
+
* - WORKER: Only background workers and schedulers (no HTTP server)
|
|
7
|
+
* - HYBRID: Both HTTP server and workers (default)
|
|
8
|
+
*/
|
|
1
9
|
export declare enum ApplicationMode {
|
|
2
10
|
HTTP = "http",
|
|
3
11
|
WORKER = "worker",
|
|
4
12
|
HYBRID = "hybrid"
|
|
5
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the current application mode from environment variables
|
|
16
|
+
* Supports both APP_MODE and MODE environment variables
|
|
17
|
+
*
|
|
18
|
+
* @returns The current application mode
|
|
19
|
+
*/
|
|
6
20
|
export declare function getApplicationMode(): ApplicationMode;
|
|
21
|
+
/**
|
|
22
|
+
* Check if the current mode should process queues and scheduled tasks
|
|
23
|
+
*
|
|
24
|
+
* @returns True if workers should be registered
|
|
25
|
+
*/
|
|
7
26
|
export declare function shouldProcessQueues(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Check if the current mode should start HTTP server
|
|
29
|
+
*
|
|
30
|
+
* @returns True if HTTP server should be started
|
|
31
|
+
*/
|
|
8
32
|
export declare function shouldStartHttpServer(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Check if running in HTTP-only mode
|
|
35
|
+
*
|
|
36
|
+
* @returns True if running in HTTP-only mode
|
|
37
|
+
*/
|
|
9
38
|
export declare function isHttpMode(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if running in Worker-only mode
|
|
41
|
+
*
|
|
42
|
+
* @returns True if running in Worker-only mode
|
|
43
|
+
*/
|
|
10
44
|
export declare function isWorkerMode(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Check if running in Hybrid mode
|
|
47
|
+
*
|
|
48
|
+
* @returns True if running in Hybrid mode
|
|
49
|
+
*/
|
|
11
50
|
export declare function isHybridMode(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Get a human-readable description of the current mode
|
|
53
|
+
*
|
|
54
|
+
* @returns Description of the current mode
|
|
55
|
+
*/
|
|
12
56
|
export declare function getModeDescription(): string;
|