@mondart/nestjs-common-module-caching 3.1.5 → 3.2.0

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 (37) hide show
  1. package/README.md +143 -0
  2. package/dist/caching.module.d.ts.map +1 -1
  3. package/dist/caching.module.js +10 -2
  4. package/dist/caching.module.js.map +1 -1
  5. package/dist/constants/caching.const.d.ts +1 -0
  6. package/dist/constants/caching.const.d.ts.map +1 -1
  7. package/dist/constants/caching.const.js +2 -1
  8. package/dist/constants/caching.const.js.map +1 -1
  9. package/dist/decorators/distributed-lock.decorator.d.ts +3 -0
  10. package/dist/decorators/distributed-lock.decorator.d.ts.map +1 -0
  11. package/dist/decorators/distributed-lock.decorator.js +8 -0
  12. package/dist/decorators/distributed-lock.decorator.js.map +1 -0
  13. package/dist/errors/distributed-lock-lost.error.d.ts +5 -0
  14. package/dist/errors/distributed-lock-lost.error.d.ts.map +1 -0
  15. package/dist/errors/distributed-lock-lost.error.js +12 -0
  16. package/dist/errors/distributed-lock-lost.error.js.map +1 -0
  17. package/dist/explorers/distributed-lock.explorer.d.ts +14 -0
  18. package/dist/explorers/distributed-lock.explorer.d.ts.map +1 -0
  19. package/dist/explorers/distributed-lock.explorer.js +70 -0
  20. package/dist/explorers/distributed-lock.explorer.js.map +1 -0
  21. package/dist/index.d.ts +5 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +5 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/interfaces/distributed-lock.interface.d.ts +18 -0
  26. package/dist/interfaces/distributed-lock.interface.d.ts.map +1 -0
  27. package/dist/interfaces/distributed-lock.interface.js +3 -0
  28. package/dist/interfaces/distributed-lock.interface.js.map +1 -0
  29. package/dist/services/caching.service.d.ts +2 -1
  30. package/dist/services/caching.service.d.ts.map +1 -1
  31. package/dist/services/caching.service.js +4 -0
  32. package/dist/services/caching.service.js.map +1 -1
  33. package/dist/services/distributed-lock.service.d.ts +17 -0
  34. package/dist/services/distributed-lock.service.d.ts.map +1 -0
  35. package/dist/services/distributed-lock.service.js +161 -0
  36. package/dist/services/distributed-lock.service.js.map +1 -0
  37. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # @mondart/nestjs-common-module-caching
2
+
3
+ Redis-backed caching for NestJS: a `CachingService` for direct key/value
4
+ access, an HTTP response-caching interceptor, and a `DistributedLockService`
5
+ for coordinating work across multiple instances of the same service (e.g. so
6
+ only one replica runs a given cron tick).
7
+
8
+ ## Registration
9
+
10
+ ```ts
11
+ import { CachingModule } from '@mondart/nestjs-common-module-caching';
12
+
13
+ @Module({
14
+ imports: [
15
+ CachingModule.register({
16
+ host: 'localhost',
17
+ port: 6379,
18
+ password: 'secret',
19
+ database: 0,
20
+ namespace: 'my-service',
21
+ ttl: 60_000, // default TTL in ms
22
+ }),
23
+ ],
24
+ })
25
+ export class AppModule {}
26
+ ```
27
+
28
+ Or asynchronously:
29
+
30
+ ```ts
31
+ CachingModule.registerAsync({
32
+ imports: [ConfigModule],
33
+ inject: [ConfigService],
34
+ useFactory: (config: ConfigService) => ({
35
+ host: config.get('REDIS_HOST'),
36
+ port: config.get('REDIS_PORT'),
37
+ password: config.get('REDIS_PASSWORD'),
38
+ }),
39
+ });
40
+ ```
41
+
42
+ `CachingModule` is `@Global()`, so `CachingService` and
43
+ `DistributedLockService` are available for injection anywhere without
44
+ re-importing the module.
45
+
46
+ ## CachingService
47
+
48
+ ```ts
49
+ constructor(private readonly cachingService: CachingService) {}
50
+
51
+ await this.cachingService.set('user:42', user, 60); // ttlSeconds
52
+ const user = await this.cachingService.get<User>('user:42');
53
+ await this.cachingService.setMany([{ key: 'a', value: 1, ttlSeconds: 30 }]);
54
+ const [a, b] = await this.cachingService.getMany<number>(['a', 'b']);
55
+ await this.cachingService.has('user:42');
56
+ await this.cachingService.ttl('user:42');
57
+ await this.cachingService.del('user:42');
58
+ await this.cachingService.delMany(['a', 'b']);
59
+ await this.cachingService.clear();
60
+ ```
61
+
62
+ ## Caching HTTP responses
63
+
64
+ `CachingModule` registers `CachingInterceptor` globally, but it only caches a
65
+ `GET` route when the handler (or controller) is explicitly opted in — nothing
66
+ is cached by default.
67
+
68
+ ```ts
69
+ import {
70
+ UseCachingInterceptorDecorator,
71
+ SkipCachingInterceptorDecorator,
72
+ } from '@mondart/nestjs-common-module-caching';
73
+
74
+ @UseCachingInterceptorDecorator({ ttl: 30_000 })
75
+ @Get()
76
+ findAll() { ... }
77
+
78
+ @SkipCachingInterceptorDecorator()
79
+ @Get('live')
80
+ findLive() { ... } // never cached, even if the controller opts in
81
+ ```
82
+
83
+ `key`/`ttl` accept the same static value or factory function types as
84
+ `@nestjs/cache-manager`'s own `CacheKey`/`CacheTTL`. When no `key` is given,
85
+ requests are cached per `ControllerName_methodName:<url+query hash>`.
86
+
87
+ ## Distributed locking
88
+
89
+ Use this to stop the same piece of work (typically a `@Cron()` handler)
90
+ running concurrently across multiple instances of a service.
91
+
92
+ ### Programmatic: `DistributedLockService.runExclusive`
93
+
94
+ ```ts
95
+ constructor(private readonly lockService: DistributedLockService) {}
96
+
97
+ @Cron('*/5 * * * *')
98
+ async syncJob() {
99
+ await this.lockService.runExclusive(
100
+ 'sync-job',
101
+ async ({ signal }) => {
102
+ for (const item of items) {
103
+ if (signal.aborted) break; // lock could no longer be renewed
104
+ await process(item);
105
+ }
106
+ },
107
+ { ttlMs: 30_000, autoExtend: true }, // autoExtend defaults to true
108
+ );
109
+ }
110
+ ```
111
+
112
+ - Returns `undefined` without invoking the callback when another instance
113
+ already holds the lock — the expected outcome on replicas that lose the
114
+ race for a given tick.
115
+ - With `autoExtend` (default `true`), the lock is renewed on an interval
116
+ (`ttlMs / 3` by default, or `extensionIntervalMs`) for as long as the
117
+ callback runs. If renewal ever falls behind the lock's real TTL, the
118
+ callback's `signal` is aborted so long-running work can check
119
+ `signal.aborted` and stop early instead of continuing to run without
120
+ exclusivity.
121
+ - `acquire`, `release`, and `extend` are also available individually for
122
+ manual lock management.
123
+
124
+ ### Declarative: `@DistributedLockDecorator`
125
+
126
+ ```ts
127
+ import { DistributedLockDecorator } from '@mondart/nestjs-common-module-caching';
128
+
129
+ @Cron('*/5 * * * *')
130
+ @DistributedLockDecorator({ key: 'sync-job', ttlMs: 30_000 })
131
+ async syncJob() { ... }
132
+ ```
133
+
134
+ `key` can also be a function of the method's arguments, e.g.
135
+ `key: (tenantId: string) => \`sync-job:${tenantId}\`` to scope the lock per
136
+ call. This works on methods that Nest itself never routes through an
137
+ interceptor (like `@Cron()` handlers) because `DistributedLockExplorer`
138
+ wraps decorated methods directly at application bootstrap, rather than
139
+ relying on the request pipeline.
140
+
141
+ Both approaches share the same `DistributedLockService` under the hood, so
142
+ lock keys are namespaced the same way (`CachingModuleOptions.namespace`,
143
+ if set) regardless of which style you use.
@@ -1 +1 @@
1
- {"version":3,"file":"caching.module.d.ts","sourceRoot":"","sources":["../src/caching.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EAEL,yBAAyB,EAEzB,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAMxC,qBAEa,aAAa;IAKxB,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa;IAoD7D,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,yBAAyB,GAAG,aAAa;IAiDvE,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAWzC,OAAO,CAAC,MAAM,CAAC,oBAAoB;CA2CpC"}
1
+ {"version":3,"file":"caching.module.d.ts","sourceRoot":"","sources":["../src/caching.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,gBAAgB,CAAC;AAGzE,OAAO,EAEL,yBAAyB,EAEzB,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAQxC,qBAEa,aAAa;IAKxB,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa;IAuD7D,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,yBAAyB,GAAG,aAAa;IAoDvE,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAWzC,OAAO,CAAC,MAAM,CAAC,oBAAoB;CA2CpC"}
@@ -48,11 +48,14 @@ const caching_interface_1 = require("./interfaces/caching.interface");
48
48
  const redis_1 = __importStar(require("@keyv/redis"));
49
49
  const core_1 = require("@nestjs/core");
50
50
  const caching_interceptor_1 = require("./interceptors/caching.interceptor");
51
+ const distributed_lock_service_1 = require("./services/distributed-lock.service");
52
+ const distributed_lock_explorer_1 = require("./explorers/distributed-lock.explorer");
51
53
  let CachingModule = CachingModule_1 = class CachingModule {
52
54
  static register(options) {
53
55
  return {
54
56
  module: CachingModule_1,
55
57
  imports: [
58
+ core_1.DiscoveryModule,
56
59
  cache_manager_1.CacheModule.register({
57
60
  isGlobal: true,
58
61
  useFactory: async (cachingOptions) => ({
@@ -88,8 +91,10 @@ let CachingModule = CachingModule_1 = class CachingModule {
88
91
  useClass: caching_interceptor_1.CachingInterceptor,
89
92
  },
90
93
  caching_service_1.CachingService,
94
+ distributed_lock_service_1.DistributedLockService,
95
+ distributed_lock_explorer_1.DistributedLockExplorer,
91
96
  ],
92
- exports: [caching_service_1.CachingService, cache_manager_1.CacheModule],
97
+ exports: [caching_service_1.CachingService, distributed_lock_service_1.DistributedLockService, cache_manager_1.CacheModule],
93
98
  };
94
99
  }
95
100
  static registerAsync(options) {
@@ -97,6 +102,7 @@ let CachingModule = CachingModule_1 = class CachingModule {
97
102
  return {
98
103
  module: CachingModule_1,
99
104
  imports: [
105
+ core_1.DiscoveryModule,
100
106
  ...(options.imports || []),
101
107
  asyncOptionsProvider,
102
108
  cache_manager_1.CacheModule.registerAsync({
@@ -131,8 +137,10 @@ let CachingModule = CachingModule_1 = class CachingModule {
131
137
  useFactory: (cacheManager) => new caching_service_1.CachingService(cacheManager),
132
138
  inject: [cache_manager_1.CACHE_MANAGER],
133
139
  },
140
+ distributed_lock_service_1.DistributedLockService,
141
+ distributed_lock_explorer_1.DistributedLockExplorer,
134
142
  ],
135
- exports: [caching_service_1.CachingService, cache_manager_1.CacheModule],
143
+ exports: [caching_service_1.CachingService, distributed_lock_service_1.DistributedLockService, cache_manager_1.CacheModule],
136
144
  };
137
145
  }
138
146
  static createAsyncOptionsProvider(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"caching.module.js","sourceRoot":"","sources":["../src/caching.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"caching.module.js","sourceRoot":"","sources":["../src/caching.module.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export declare const SKIP_CACHING_INTERCEPTOR_KEY = "skipCachingInterceptor";
2
2
  export declare const USE_CACHING_INTERCEPTOR_KEY = "useCachingInterceptor";
3
+ export declare const DISTRIBUTED_LOCK_KEY = "distributedLock";
3
4
  //# sourceMappingURL=caching.const.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"caching.const.d.ts","sourceRoot":"","sources":["../../src/constants/caching.const.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,2BAA2B,CAAC;AACrE,eAAO,MAAM,2BAA2B,0BAA0B,CAAC"}
1
+ {"version":3,"file":"caching.const.d.ts","sourceRoot":"","sources":["../../src/constants/caching.const.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,2BAA2B,CAAC;AACrE,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AACnE,eAAO,MAAM,oBAAoB,oBAAoB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.USE_CACHING_INTERCEPTOR_KEY = exports.SKIP_CACHING_INTERCEPTOR_KEY = void 0;
3
+ exports.DISTRIBUTED_LOCK_KEY = exports.USE_CACHING_INTERCEPTOR_KEY = exports.SKIP_CACHING_INTERCEPTOR_KEY = void 0;
4
4
  exports.SKIP_CACHING_INTERCEPTOR_KEY = 'skipCachingInterceptor';
5
5
  exports.USE_CACHING_INTERCEPTOR_KEY = 'useCachingInterceptor';
6
+ exports.DISTRIBUTED_LOCK_KEY = 'distributedLock';
6
7
  //# sourceMappingURL=caching.const.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"caching.const.js","sourceRoot":"","sources":["../../src/constants/caching.const.ts"],"names":[],"mappings":";;;AAAa,QAAA,4BAA4B,GAAG,wBAAwB,CAAC;AACxD,QAAA,2BAA2B,GAAG,uBAAuB,CAAC"}
1
+ {"version":3,"file":"caching.const.js","sourceRoot":"","sources":["../../src/constants/caching.const.ts"],"names":[],"mappings":";;;AAAa,QAAA,4BAA4B,GAAG,wBAAwB,CAAC;AACxD,QAAA,2BAA2B,GAAG,uBAAuB,CAAC;AACtD,QAAA,oBAAoB,GAAG,iBAAiB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { DistributedLockMethodOptions } from '../interfaces/distributed-lock.interface';
2
+ export declare const DistributedLockDecorator: (options: DistributedLockMethodOptions) => import("@nestjs/common").CustomDecorator<string>;
3
+ //# sourceMappingURL=distributed-lock.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/distributed-lock.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AAkBxF,eAAO,MAAM,wBAAwB,GACnC,SAAS,4BAA4B,qDACQ,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DistributedLockDecorator = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const caching_const_1 = require("../constants/caching.const");
6
+ const DistributedLockDecorator = (options) => (0, common_1.SetMetadata)(caching_const_1.DISTRIBUTED_LOCK_KEY, options);
7
+ exports.DistributedLockDecorator = DistributedLockDecorator;
8
+ //# sourceMappingURL=distributed-lock.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.decorator.js","sourceRoot":"","sources":["../../src/decorators/distributed-lock.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAC7C,8DAAkE;AAmB3D,MAAM,wBAAwB,GAAG,CACtC,OAAqC,EACrC,EAAE,CAAC,IAAA,oBAAW,EAAC,oCAAoB,EAAE,OAAO,CAAC,CAAC;AAFnC,QAAA,wBAAwB,4BAEW"}
@@ -0,0 +1,5 @@
1
+ export declare class DistributedLockLostError extends Error {
2
+ readonly key: string;
3
+ constructor(key: string);
4
+ }
5
+ //# sourceMappingURL=distributed-lock-lost.error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock-lost.error.d.ts","sourceRoot":"","sources":["../../src/errors/distributed-lock-lost.error.ts"],"names":[],"mappings":"AAAA,qBAAa,wBAAyB,SAAQ,KAAK;aACrB,GAAG,EAAE,MAAM;gBAAX,GAAG,EAAE,MAAM;CAMxC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DistributedLockLostError = void 0;
4
+ class DistributedLockLostError extends Error {
5
+ constructor(key) {
6
+ super(`Distributed lock "${key}" was lost before the protected work finished`);
7
+ this.key = key;
8
+ this.name = 'DistributedLockLostError';
9
+ }
10
+ }
11
+ exports.DistributedLockLostError = DistributedLockLostError;
12
+ //# sourceMappingURL=distributed-lock-lost.error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock-lost.error.js","sourceRoot":"","sources":["../../src/errors/distributed-lock-lost.error.ts"],"names":[],"mappings":";;;AAAA,MAAa,wBAAyB,SAAQ,KAAK;IACjD,YAA4B,GAAW;QACrC,KAAK,CACH,qBAAqB,GAAG,+CAA+C,CACxE,CAAC;QAHwB,QAAG,GAAH,GAAG,CAAQ;QAIrC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAPD,4DAOC"}
@@ -0,0 +1,14 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { DiscoveryService, MetadataScanner, Reflector } from '@nestjs/core';
3
+ import { DistributedLockService } from '../services/distributed-lock.service';
4
+ export declare class DistributedLockExplorer implements OnModuleInit {
5
+ private readonly discoveryService;
6
+ private readonly metadataScanner;
7
+ private readonly reflector;
8
+ private readonly distributedLockService;
9
+ private readonly logger;
10
+ constructor(discoveryService: DiscoveryService, metadataScanner: MetadataScanner, reflector: Reflector, distributedLockService: DistributedLockService);
11
+ onModuleInit(): void;
12
+ private wrapIfDecorated;
13
+ }
14
+ //# sourceMappingURL=distributed-lock.explorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.explorer.d.ts","sourceRoot":"","sources":["../../src/explorers/distributed-lock.explorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAI5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAU9E,qBACa,uBAAwB,YAAW,YAAY;IAIxD,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IANzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAGhD,gBAAgB,EAAE,gBAAgB,EAClC,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,SAAS,EACpB,sBAAsB,EAAE,sBAAsB;IAGjE,YAAY,IAAI,IAAI;IAyBpB,OAAO,CAAC,eAAe;CAkCxB"}
@@ -0,0 +1,70 @@
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 DistributedLockExplorer_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.DistributedLockExplorer = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const core_1 = require("@nestjs/core");
16
+ const caching_const_1 = require("../constants/caching.const");
17
+ const distributed_lock_service_1 = require("../services/distributed-lock.service");
18
+ let DistributedLockExplorer = DistributedLockExplorer_1 = class DistributedLockExplorer {
19
+ constructor(discoveryService, metadataScanner, reflector, distributedLockService) {
20
+ this.discoveryService = discoveryService;
21
+ this.metadataScanner = metadataScanner;
22
+ this.reflector = reflector;
23
+ this.distributedLockService = distributedLockService;
24
+ this.logger = new common_1.Logger(DistributedLockExplorer_1.name);
25
+ }
26
+ onModuleInit() {
27
+ const wrappers = [
28
+ ...this.discoveryService.getProviders(),
29
+ ...this.discoveryService.getControllers(),
30
+ ];
31
+ for (const wrapper of wrappers) {
32
+ const instance = wrapper.instance;
33
+ if (!instance || typeof instance !== 'object') {
34
+ continue;
35
+ }
36
+ const prototype = Object.getPrototypeOf(instance);
37
+ if (!prototype) {
38
+ continue;
39
+ }
40
+ for (const methodName of this.metadataScanner.getAllMethodNames(prototype)) {
41
+ this.wrapIfDecorated(instance, prototype, methodName);
42
+ }
43
+ }
44
+ }
45
+ wrapIfDecorated(instance, prototype, methodName) {
46
+ const originalMethod = instance[methodName];
47
+ if (typeof originalMethod !== 'function') {
48
+ return;
49
+ }
50
+ const options = this.reflector.get(caching_const_1.DISTRIBUTED_LOCK_KEY, originalMethod);
51
+ if (!options) {
52
+ return;
53
+ }
54
+ const distributedLockService = this.distributedLockService;
55
+ instance[methodName] = function (...args) {
56
+ const key = typeof options.key === 'function' ? options.key(...args) : options.key;
57
+ return distributedLockService.runExclusive(key, () => originalMethod.apply(this, args), options);
58
+ };
59
+ this.logger.debug(`Wrapped ${prototype.constructor.name}.${methodName} with a distributed lock`);
60
+ }
61
+ };
62
+ exports.DistributedLockExplorer = DistributedLockExplorer;
63
+ exports.DistributedLockExplorer = DistributedLockExplorer = DistributedLockExplorer_1 = __decorate([
64
+ (0, common_1.Injectable)(),
65
+ __metadata("design:paramtypes", [core_1.DiscoveryService,
66
+ core_1.MetadataScanner,
67
+ core_1.Reflector,
68
+ distributed_lock_service_1.DistributedLockService])
69
+ ], DistributedLockExplorer);
70
+ //# sourceMappingURL=distributed-lock.explorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.explorer.js","sourceRoot":"","sources":["../../src/explorers/distributed-lock.explorer.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAkE;AAClE,uCAA4E;AAE5E,8DAAkE;AAElE,mFAA8E;AAWvE,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IAGlC,YACmB,gBAAkC,EAClC,eAAgC,EAChC,SAAoB,EACpB,sBAA8C;QAH9C,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,oBAAe,GAAf,eAAe,CAAiB;QAChC,cAAS,GAAT,SAAS,CAAW;QACpB,2BAAsB,GAAtB,sBAAsB,CAAwB;QANhD,WAAM,GAAG,IAAI,eAAM,CAAC,yBAAuB,CAAC,IAAI,CAAC,CAAC;IAOhE,CAAC;IAEJ,YAAY;QACV,MAAM,QAAQ,GAAsB;YAClC,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE;YACvC,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE;SAC1C,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAClC,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC9C,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YAClD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS;YACX,CAAC;YAED,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAC7D,SAAS,CACV,EAAE,CAAC;gBACF,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;IACH,CAAC;IAEO,eAAe,CACrB,QAA6B,EAC7B,SAAiB,EACjB,UAAkB;QAElB,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAChC,oCAAoB,EACpB,cAAc,CACf,CAAC;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,MAAM,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,CAAC;QAC3D,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAyB,GAAG,IAAe;YAChE,MAAM,GAAG,GACP,OAAO,OAAO,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;YAEzE,OAAO,sBAAsB,CAAC,YAAY,CACxC,GAAG,EACH,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EACtC,OAAO,CACR,CAAC;QACJ,CAAC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,WAAY,SAAS,CAAC,WAAgC,CAAC,IAAI,IAAI,UAAU,0BAA0B,CACpG,CAAC;IACJ,CAAC;CACF,CAAA;AArEY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,mBAAU,GAAE;qCAK0B,uBAAgB;QACjB,sBAAe;QACrB,gBAAS;QACI,iDAAsB;GAPtD,uBAAuB,CAqEnC"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  export * from './caching.module';
2
2
  export * from './services/caching.service';
3
+ export * from './services/distributed-lock.service';
3
4
  export * from './interfaces/caching.interface';
5
+ export * from './interfaces/distributed-lock.interface';
4
6
  export * from './interfaces/use-caching-interceptor-decorator-params.interface';
5
7
  export * from './constants/caching.const';
6
8
  export * from './decorators/use-caching-interceptor.decorator';
7
9
  export * from './decorators/skip-caching-interceptor.decorator';
10
+ export * from './decorators/distributed-lock.decorator';
11
+ export * from './explorers/distributed-lock.explorer';
12
+ export * from './errors/distributed-lock-lost.error';
8
13
  export * from './interceptors/caching.interceptor';
9
14
  export * from './factories/caching-query-key.facroty';
10
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iEAAiE,CAAC;AAChF,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gDAAgD,CAAC;AAC/D,cAAc,iDAAiD,CAAC;AAChE,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yCAAyC,CAAC;AACxD,cAAc,iEAAiE,CAAC;AAChF,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gDAAgD,CAAC;AAC/D,cAAc,iDAAiD,CAAC;AAChE,cAAc,yCAAyC,CAAC;AACxD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC"}
package/dist/index.js CHANGED
@@ -16,11 +16,16 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./caching.module"), exports);
18
18
  __exportStar(require("./services/caching.service"), exports);
19
+ __exportStar(require("./services/distributed-lock.service"), exports);
19
20
  __exportStar(require("./interfaces/caching.interface"), exports);
21
+ __exportStar(require("./interfaces/distributed-lock.interface"), exports);
20
22
  __exportStar(require("./interfaces/use-caching-interceptor-decorator-params.interface"), exports);
21
23
  __exportStar(require("./constants/caching.const"), exports);
22
24
  __exportStar(require("./decorators/use-caching-interceptor.decorator"), exports);
23
25
  __exportStar(require("./decorators/skip-caching-interceptor.decorator"), exports);
26
+ __exportStar(require("./decorators/distributed-lock.decorator"), exports);
27
+ __exportStar(require("./explorers/distributed-lock.explorer"), exports);
28
+ __exportStar(require("./errors/distributed-lock-lost.error"), exports);
24
29
  __exportStar(require("./interceptors/caching.interceptor"), exports);
25
30
  __exportStar(require("./factories/caching-query-key.facroty"), exports);
26
31
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,6DAA2C;AAC3C,iEAA+C;AAC/C,kGAAgF;AAChF,4DAA0C;AAC1C,iFAA+D;AAC/D,kFAAgE;AAChE,qEAAmD;AACnD,wEAAsD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,6DAA2C;AAC3C,sEAAoD;AACpD,iEAA+C;AAC/C,0EAAwD;AACxD,kGAAgF;AAChF,4DAA0C;AAC1C,iFAA+D;AAC/D,kFAAgE;AAChE,0EAAwD;AACxD,wEAAsD;AACtD,uEAAqD;AACrD,qEAAmD;AACnD,wEAAsD"}
@@ -0,0 +1,18 @@
1
+ export interface DistributedLockOptions {
2
+ ttlMs: number;
3
+ autoExtend?: boolean;
4
+ extensionIntervalMs?: number;
5
+ }
6
+ export interface DistributedLock {
7
+ key: string;
8
+ token: string;
9
+ ttlMs: number;
10
+ }
11
+ export interface DistributedLockCallbackContext {
12
+ signal: AbortSignal;
13
+ }
14
+ export type DistributedLockCallback<T> = (context: DistributedLockCallbackContext) => Promise<T>;
15
+ export interface DistributedLockMethodOptions extends DistributedLockOptions {
16
+ key: string | ((...args: any[]) => string);
17
+ }
18
+ //# sourceMappingURL=distributed-lock.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/distributed-lock.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IAMd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,8BAA8B;IAM7C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,CACvC,OAAO,EAAE,8BAA8B,KACpC,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhB,MAAM,WAAW,4BAA6B,SAAQ,sBAAsB;IAK1E,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,CAAC;CAC5C"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=distributed-lock.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.interface.js","sourceRoot":"","sources":["../../src/interfaces/distributed-lock.interface.ts"],"names":[],"mappings":""}
@@ -1,10 +1,11 @@
1
1
  import { Cache } from 'cache-manager';
2
- import { Keyv } from '@keyv/redis';
2
+ import { Keyv, RedisClientConnectionType } from '@keyv/redis';
3
3
  export declare class CachingService {
4
4
  private cacheManager;
5
5
  private readonly logger;
6
6
  constructor(cacheManager: Cache);
7
7
  getStore(): Keyv<any>;
8
+ getRedisClient(): Promise<RedisClientConnectionType>;
8
9
  get<T>(key: string): Promise<T | undefined>;
9
10
  getMany<T>(keys?: string[]): Promise<T[] | undefined>;
10
11
  set<T>(key: string, value: T, ttlSeconds?: number): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"caching.service.d.ts","sourceRoot":"","sources":["../../src/services/caching.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,qBACa,cAAc;IAIU,OAAO,CAAC,YAAY;IAHvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;gBACwC,YAAY,EAAE,KAAK;IAkB9D,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC;IAQf,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAc3C,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;IAerD,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAanE,OAAO,CAAC,CAAC,EACb,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GACrD,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAapD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQlC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAOzC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAQzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQlC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAGpD"}
1
+ {"version":3,"file":"caching.service.d.ts","sourceRoot":"","sources":["../../src/services/caching.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAkB,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAEzE,qBACa,cAAc;IAIU,OAAO,CAAC,YAAY;IAHvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;gBACwC,YAAY,EAAE,KAAK;IAkB9D,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC;IAOf,cAAc,IAAI,OAAO,CAAC,yBAAyB,CAAC;IASpD,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAc3C,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;IAerD,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAanE,OAAO,CAAC,CAAC,EACb,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GACrD,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAapD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQlC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAOzC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAQzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQlC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAGpD"}
@@ -36,6 +36,10 @@ let CachingService = CachingService_1 = class CachingService {
36
36
  getStore() {
37
37
  return this.cacheManager.stores?.[0];
38
38
  }
39
+ async getRedisClient() {
40
+ const redisStore = this.getStore().opts.store;
41
+ return redisStore.getClient();
42
+ }
39
43
  async get(key) {
40
44
  const result = await this.cacheManager.get(key);
41
45
  if (result) {
@@ -1 +1 @@
1
- {"version":3,"file":"caching.service.js","sourceRoot":"","sources":["../../src/services/caching.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"caching.service.js","sourceRoot":"","sources":["../../src/services/caching.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { CachingModuleOptions } from '../interfaces/caching.interface';
2
+ import { DistributedLock, DistributedLockCallback, DistributedLockOptions } from '../interfaces/distributed-lock.interface';
3
+ import { CachingService } from './caching.service';
4
+ export declare class DistributedLockService {
5
+ private readonly cachingService;
6
+ private readonly cachingOptions;
7
+ private readonly logger;
8
+ constructor(cachingService: CachingService, cachingOptions: CachingModuleOptions);
9
+ acquire(key: string, ttlMs: number): Promise<DistributedLock | null>;
10
+ release(lock: DistributedLock): Promise<boolean>;
11
+ extend(lock: DistributedLock, ttlMs?: number): Promise<boolean>;
12
+ runExclusive<T>(key: string, callback: DistributedLockCallback<T>, options: DistributedLockOptions): Promise<T | undefined>;
13
+ private startExtension;
14
+ private getNamespacedKey;
15
+ private validateTtl;
16
+ }
17
+ //# sourceMappingURL=distributed-lock.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.service.d.ts","sourceRoot":"","sources":["../../src/services/distributed-lock.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,oBAAoB,EACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgBnD,qBACa,sBAAsB;IAM/B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAPjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;gBAGgB,cAAc,EAAE,cAAc,EAE9B,cAAc,EAAE,oBAAoB;IAUjD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAwBpE,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBhD,MAAM,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,SAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BnE,YAAY,CAAC,CAAC,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC,EACpC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IA4DzB,OAAO,CAAC,cAAc;IA0CtB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,WAAW;CAKpB"}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var DistributedLockService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.DistributedLockService = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const crypto_1 = require("crypto");
19
+ const caching_interface_1 = require("../interfaces/caching.interface");
20
+ const distributed_lock_lost_error_1 = require("../errors/distributed-lock-lost.error");
21
+ const caching_service_1 = require("./caching.service");
22
+ const RELEASE_SCRIPT = `
23
+ if redis.call('get', KEYS[1]) == ARGV[1] then
24
+ return redis.call('del', KEYS[1])
25
+ end
26
+ return 0
27
+ `;
28
+ const EXTEND_SCRIPT = `
29
+ if redis.call('get', KEYS[1]) == ARGV[1] then
30
+ return redis.call('pexpire', KEYS[1], ARGV[2])
31
+ end
32
+ return 0
33
+ `;
34
+ let DistributedLockService = DistributedLockService_1 = class DistributedLockService {
35
+ constructor(cachingService, cachingOptions) {
36
+ this.cachingService = cachingService;
37
+ this.cachingOptions = cachingOptions;
38
+ this.logger = new common_1.Logger(DistributedLockService_1.name, {
39
+ timestamp: true,
40
+ });
41
+ }
42
+ async acquire(key, ttlMs) {
43
+ this.validateTtl(ttlMs);
44
+ if (!key.trim()) {
45
+ throw new Error('Distributed lock key must not be empty');
46
+ }
47
+ const namespacedKey = this.getNamespacedKey(key);
48
+ const token = (0, crypto_1.randomUUID)();
49
+ const redis = await this.cachingService.getRedisClient();
50
+ const result = await redis.set(namespacedKey, token, {
51
+ PX: ttlMs,
52
+ NX: true,
53
+ });
54
+ return result === 'OK' ? { key: namespacedKey, token, ttlMs } : null;
55
+ }
56
+ async release(lock) {
57
+ const redis = await this.cachingService.getRedisClient();
58
+ const result = await redis.eval(RELEASE_SCRIPT, {
59
+ keys: [lock.key],
60
+ arguments: [lock.token],
61
+ });
62
+ return Number(result) === 1;
63
+ }
64
+ async extend(lock, ttlMs = lock.ttlMs) {
65
+ this.validateTtl(ttlMs);
66
+ const redis = await this.cachingService.getRedisClient();
67
+ const result = await redis.eval(EXTEND_SCRIPT, {
68
+ keys: [lock.key],
69
+ arguments: [lock.token, String(ttlMs)],
70
+ });
71
+ if (Number(result) === 1) {
72
+ lock.ttlMs = ttlMs;
73
+ return true;
74
+ }
75
+ return false;
76
+ }
77
+ async runExclusive(key, callback, options) {
78
+ const lock = await this.acquire(key, options.ttlMs);
79
+ if (!lock) {
80
+ this.logger.debug(`Skipped "${key}": lock is already held by another instance`);
81
+ return undefined;
82
+ }
83
+ const autoExtend = options.autoExtend ?? true;
84
+ const abortController = new AbortController();
85
+ let extensionInterval;
86
+ let workError;
87
+ let releaseError;
88
+ let result;
89
+ try {
90
+ extensionInterval = autoExtend
91
+ ? this.startExtension(lock, abortController, options.extensionIntervalMs)
92
+ : undefined;
93
+ result = await callback({ signal: abortController.signal });
94
+ }
95
+ catch (error) {
96
+ workError = error;
97
+ }
98
+ finally {
99
+ if (extensionInterval) {
100
+ clearInterval(extensionInterval);
101
+ }
102
+ try {
103
+ await this.release(lock);
104
+ }
105
+ catch (error) {
106
+ releaseError = error;
107
+ }
108
+ }
109
+ if (releaseError) {
110
+ this.logger.error(`Failed to release distributed lock "${lock.key}": ${releaseError.message}`);
111
+ }
112
+ if (workError) {
113
+ throw workError;
114
+ }
115
+ if (releaseError) {
116
+ throw releaseError;
117
+ }
118
+ return result;
119
+ }
120
+ startExtension(lock, abortController, configuredInterval) {
121
+ const intervalMs = configuredInterval ?? Math.max(100, Math.floor(lock.ttlMs / 3));
122
+ if (intervalMs <= 0 || intervalMs >= lock.ttlMs) {
123
+ throw new Error('Lock extension interval must be positive and shorter than its TTL');
124
+ }
125
+ let deadline = Date.now() + lock.ttlMs;
126
+ return setInterval(() => {
127
+ void this.extend(lock)
128
+ .then((extended) => {
129
+ if (extended) {
130
+ deadline = Date.now() + lock.ttlMs;
131
+ return;
132
+ }
133
+ this.logger.warn(`Distributed lock "${lock.key}" is no longer owned by this instance`);
134
+ abortController.abort(new distributed_lock_lost_error_1.DistributedLockLostError(lock.key));
135
+ })
136
+ .catch((error) => {
137
+ this.logger.warn(`Failed to extend distributed lock "${lock.key}": ${error.message}`);
138
+ if (Date.now() >= deadline) {
139
+ this.logger.error(`Distributed lock "${lock.key}" expired while work was still running`);
140
+ abortController.abort(new distributed_lock_lost_error_1.DistributedLockLostError(lock.key));
141
+ }
142
+ });
143
+ }, intervalMs).unref();
144
+ }
145
+ getNamespacedKey(key) {
146
+ const namespace = this.cachingOptions.namespace?.replace(/:+$/, '');
147
+ return namespace ? `${namespace}:${key}` : key;
148
+ }
149
+ validateTtl(ttlMs) {
150
+ if (!Number.isInteger(ttlMs) || ttlMs <= 0) {
151
+ throw new Error('Distributed lock TTL must be a positive integer');
152
+ }
153
+ }
154
+ };
155
+ exports.DistributedLockService = DistributedLockService;
156
+ exports.DistributedLockService = DistributedLockService = DistributedLockService_1 = __decorate([
157
+ (0, common_1.Injectable)(),
158
+ __param(1, (0, common_1.Inject)(caching_interface_1.CACHING_MODULE_OPTIONS)),
159
+ __metadata("design:paramtypes", [caching_service_1.CachingService, Object])
160
+ ], DistributedLockService);
161
+ //# sourceMappingURL=distributed-lock.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distributed-lock.service.js","sourceRoot":"","sources":["../../src/services/distributed-lock.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondart/nestjs-common-module-caching",
3
- "version": "3.1.5",
3
+ "version": "3.2.0",
4
4
  "description": "Caching module for NestJS.",
5
5
  "author": {
6
6
  "name": "Mondart"
@@ -17,7 +17,7 @@
17
17
  "build": "tsc -p tsconfig.json"
18
18
  },
19
19
  "dependencies": {
20
- "@mondart/nestjs-common-module-core": "^3.2.3",
20
+ "@mondart/nestjs-common-module-core": "^3.2.5",
21
21
  "@keyv/redis": "4.2.0",
22
22
  "@nestjs/cache-manager": "^3.0.0",
23
23
  "cache-manager": "6.4.0",