@nest-omni/core 4.1.3-2 → 4.1.3-20
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 +63 -1
- package/audit/controllers/audit.controller.d.ts +88 -0
- package/audit/controllers/audit.controller.js +74 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -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 +85 -1
- package/audit/decorators/entity-audit.decorator.js +153 -3
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +2 -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/audit-action-summary.entity.d.ts +23 -0
- package/audit/entities/audit-action-summary.entity.js +101 -0
- package/audit/entities/entity-audit-log.entity.d.ts +11 -0
- package/audit/entities/entity-audit-log.entity.js +57 -2
- package/audit/entities/entity-transaction.entity.d.ts +11 -2
- package/audit/entities/entity-transaction.entity.js +42 -3
- package/audit/entities/index.d.ts +3 -0
- package/audit/entities/index.js +3 -0
- package/audit/entities/manual-operation-log.entity.d.ts +4 -0
- package/audit/entities/manual-operation-log.entity.js +12 -1
- 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 +37 -6
- package/audit/enums/audit.enums.js +40 -7
- package/audit/index.d.ts +4 -1
- package/audit/index.js +34 -1
- package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
- package/audit/interceptors/audit-action.interceptor.js +215 -0
- package/audit/interceptors/audit.interceptor.d.ts +15 -0
- package/audit/interceptors/audit.interceptor.js +23 -1
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +187 -2
- package/audit/services/audit-action.service.d.ts +141 -0
- package/audit/services/audit-action.service.js +244 -0
- package/audit/services/audit-context.service.d.ts +97 -0
- package/audit/services/audit-context.service.js +185 -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 +230 -3
- package/audit/services/entity-audit.service.js +607 -14
- package/audit/services/index.d.ts +3 -0
- package/audit/services/index.js +3 -0
- package/audit/services/manual-audit-log.service.d.ts +134 -9
- package/audit/services/manual-audit-log.service.js +157 -40
- package/audit/services/multi-database.service.d.ts +9 -2
- package/audit/services/multi-database.service.js +9 -21
- package/audit/services/operation-description.service.d.ts +71 -2
- package/audit/services/operation-description.service.js +231 -20
- package/audit/services/transaction-audit.service.d.ts +30 -0
- package/audit/services/transaction-audit.service.js +53 -5
- package/audit/subscribers/entity-audit.subscriber.d.ts +19 -0
- package/audit/subscribers/entity-audit.subscriber.js +76 -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 +82 -2
- package/cache/cache.module.js +76 -5
- package/cache/cache.service.d.ts +140 -0
- package/cache/cache.service.js +169 -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 +83 -7
- package/cache/dependencies/db.dependency.js +89 -14
- package/cache/dependencies/file.dependency.d.ts +32 -0
- package/cache/dependencies/file.dependency.js +34 -0
- package/cache/dependencies/tag.dependency.d.ts +75 -4
- package/cache/dependencies/tag.dependency.js +145 -11
- 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 +89 -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 +43 -0
- package/cache/providers/memory-cache.provider.js +66 -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 -0
- package/common/boilerplate.polyfill.js +18 -1
- 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.d.ts +1 -1
- 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/file-upload/controllers/file-access.controller.d.ts +23 -0
- package/file-upload/controllers/file-access.controller.js +128 -0
- package/file-upload/decorators/column.decorator.d.ts +151 -0
- package/file-upload/decorators/column.decorator.js +273 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +30 -0
- package/file-upload/decorators/csv-data.decorator.js +85 -0
- package/file-upload/decorators/csv-import.decorator.d.ts +34 -0
- package/file-upload/decorators/csv-import.decorator.js +24 -0
- package/file-upload/decorators/examples/column-mapping.example.d.ts +76 -0
- package/file-upload/decorators/examples/column-mapping.example.js +122 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +30 -0
- package/file-upload/decorators/excel-data.decorator.js +85 -0
- package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
- package/file-upload/decorators/file-upload.decorator.js +172 -0
- package/file-upload/decorators/index.d.ts +5 -0
- package/file-upload/decorators/index.js +38 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/decorators/validate-data.decorator.d.ts +91 -0
- package/file-upload/decorators/validate-data.decorator.js +39 -0
- package/file-upload/dto/create-file.dto.d.ts +24 -0
- package/file-upload/dto/create-file.dto.js +112 -0
- package/file-upload/dto/find-files.dto.d.ts +15 -0
- package/file-upload/dto/find-files.dto.js +76 -0
- package/file-upload/dto/index.d.ts +4 -0
- package/file-upload/dto/index.js +20 -0
- package/file-upload/dto/pagination.dto.d.ts +7 -0
- package/file-upload/dto/pagination.dto.js +39 -0
- package/file-upload/dto/update-file.dto.d.ts +15 -0
- package/file-upload/dto/update-file.dto.js +67 -0
- package/file-upload/entities/file-metadata.entity.d.ts +25 -0
- package/file-upload/entities/file-metadata.entity.js +76 -0
- package/file-upload/entities/file.entity.d.ts +114 -0
- package/file-upload/entities/file.entity.js +350 -0
- package/file-upload/entities/index.d.ts +2 -0
- package/file-upload/entities/index.js +18 -0
- package/file-upload/enums/file-type.enum.d.ts +72 -0
- package/file-upload/enums/file-type.enum.js +212 -0
- package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
- package/file-upload/exceptions/file-upload.exception.js +120 -0
- package/file-upload/exceptions/index.d.ts +1 -0
- package/file-upload/exceptions/index.js +17 -0
- package/file-upload/file-upload.module.d.ts +89 -0
- package/file-upload/file-upload.module.js +292 -0
- package/file-upload/index.d.ts +37 -0
- package/file-upload/index.js +77 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +101 -0
- package/file-upload/interceptors/file-upload.interceptor.js +594 -0
- package/file-upload/interceptors/index.d.ts +1 -0
- package/file-upload/interceptors/index.js +17 -0
- package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
- package/file-upload/interfaces/custom-file-type.interface.js +2 -0
- package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
- package/file-upload/interfaces/file-buffer.interface.js +2 -0
- package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
- package/file-upload/interfaces/file-entity.interface.js +28 -0
- package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
- package/file-upload/interfaces/file-metadata.interface.js +2 -0
- package/file-upload/interfaces/file-processor.interface.d.ts +93 -0
- package/file-upload/interfaces/file-processor.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +74 -0
- package/file-upload/interfaces/file-upload-options.interface.js +5 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/processor-options.interface.d.ts +102 -0
- package/file-upload/interfaces/processor-options.interface.js +2 -0
- package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
- package/file-upload/interfaces/storage-provider.interface.js +2 -0
- package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
- package/file-upload/interfaces/upload-options.interface.js +2 -0
- package/file-upload/processors/csv.processor.d.ts +98 -0
- package/file-upload/processors/csv.processor.js +391 -0
- package/file-upload/processors/excel.processor.d.ts +130 -0
- package/file-upload/processors/excel.processor.js +547 -0
- package/file-upload/processors/image.processor.d.ts +199 -0
- package/file-upload/processors/image.processor.js +377 -0
- package/file-upload/providers/index.d.ts +2 -0
- package/file-upload/providers/index.js +18 -0
- package/file-upload/providers/local-storage.provider.d.ts +98 -0
- package/file-upload/providers/local-storage.provider.js +484 -0
- package/file-upload/providers/s3-storage.provider.d.ts +87 -0
- package/file-upload/providers/s3-storage.provider.js +455 -0
- package/file-upload/services/file-signature-validator.service.d.ts +118 -0
- package/file-upload/services/file-signature-validator.service.js +376 -0
- package/file-upload/services/file.service.d.ts +193 -0
- package/file-upload/services/file.service.js +638 -0
- package/file-upload/services/index.d.ts +4 -0
- package/file-upload/services/index.js +20 -0
- package/file-upload/services/malicious-file-detector.service.d.ts +300 -0
- package/file-upload/services/malicious-file-detector.service.js +1234 -0
- package/file-upload/services/mime-registry.service.d.ts +47 -0
- package/file-upload/services/mime-registry.service.js +167 -0
- package/file-upload/utils/checksum.util.d.ts +28 -0
- package/file-upload/utils/checksum.util.js +65 -0
- package/file-upload/utils/dynamic-import.util.d.ts +54 -0
- package/file-upload/utils/dynamic-import.util.js +156 -0
- package/file-upload/utils/filename.util.d.ts +59 -0
- package/file-upload/utils/filename.util.js +184 -0
- package/file-upload/utils/filepath.util.d.ts +70 -0
- package/file-upload/utils/filepath.util.js +152 -0
- package/file-upload/utils/index.d.ts +4 -0
- package/file-upload/utils/index.js +20 -0
- 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 +20 -0
- package/http-client/config/http-client.config.js +48 -21
- package/http-client/decorators/http-client.decorators.d.ts +55 -14
- package/http-client/decorators/http-client.decorators.js +154 -78
- package/http-client/entities/http-log.entity.d.ts +217 -8
- package/http-client/entities/http-log.entity.js +7 -22
- 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 +40 -0
- package/http-client/examples/advanced-usage.example.js +53 -61
- 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/examples/proxy-from-environment.example.d.ts +133 -0
- package/http-client/examples/proxy-from-environment.example.js +409 -0
- package/http-client/http-client.module.d.ts +48 -2
- package/http-client/http-client.module.js +147 -68
- package/http-client/index.d.ts +1 -1
- package/http-client/index.js +8 -0
- package/http-client/interfaces/api-client-config.interface.d.ts +80 -45
- package/http-client/interfaces/api-client-config.interface.js +3 -0
- package/http-client/interfaces/http-client-config.interface.d.ts +109 -52
- package/http-client/services/api-client-registry.service.d.ts +50 -11
- package/http-client/services/api-client-registry.service.js +90 -250
- package/http-client/services/circuit-breaker.service.d.ts +115 -2
- package/http-client/services/circuit-breaker.service.js +237 -7
- package/http-client/services/http-client.service.d.ts +124 -14
- package/http-client/services/http-client.service.js +437 -148
- package/http-client/services/http-log-query.service.d.ts +83 -0
- package/http-client/services/http-log-query.service.js +121 -13
- 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/index.d.ts +0 -1
- package/http-client/services/index.js +0 -1
- 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 +116 -7
- package/http-client/services/logging.service.js +349 -86
- package/http-client/utils/call-stack-extractor.util.d.ts +63 -0
- package/http-client/utils/call-stack-extractor.util.js +83 -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/index.d.ts +1 -0
- package/http-client/utils/index.js +1 -0
- package/http-client/utils/proxy-environment.util.d.ts +42 -0
- package/http-client/utils/proxy-environment.util.js +148 -0
- 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/http-client/utils/security-validator.util.d.ts +118 -0
- package/http-client/utils/security-validator.util.js +352 -0
- package/index.d.ts +3 -1
- package/index.js +12 -1
- package/interceptors/translation-interceptor.service.js +5 -0
- package/package.json +11 -7
- 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 +80 -0
- package/redis-lock/lock-heartbeat.service.js +232 -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 +282 -0
- package/redis-lock/redis-lock.service.js +343 -20
- package/setup/bootstrap.setup.d.ts +1 -0
- package/setup/bootstrap.setup.js +21 -0
- package/setup/index.d.ts +1 -0
- package/setup/index.js +1 -0
- package/setup/mode.setup.d.ts +44 -0
- package/setup/mode.setup.js +44 -0
- package/setup/run-in-mode.decorator.d.ts +56 -0
- package/setup/run-in-mode.decorator.js +92 -0
- package/setup/schedule.decorator.d.ts +227 -0
- package/setup/schedule.decorator.js +240 -12
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +97 -0
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +19 -17
- package/shared/services/api-config.service.d.ts +3 -0
- package/shared/services/api-config.service.js +21 -9
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- 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 +23 -0
- package/validators/custom-validate.examples.js +78 -6
- package/validators/custom-validate.validator.d.ts +108 -0
- package/validators/custom-validate.validator.js +85 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/index.d.ts +1 -0
- package/validators/index.js +1 -0
- package/validators/is-exists.validator.d.ts +26 -6
- package/validators/is-exists.validator.js +30 -7
- package/validators/is-unique.validator.d.ts +33 -7
- package/validators/is-unique.validator.js +59 -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
- package/http-client/services/cache.service.d.ts +0 -24
- package/http-client/services/cache.service.js +0 -264
- package/shared/services/validator.service.d.ts +0 -3
- package/shared/services/validator.service.js +0 -20
- /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
|
@@ -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,93 @@ 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
|
+
// Validate TTL
|
|
179
|
+
if (opts.ttl !== undefined) {
|
|
180
|
+
if (typeof opts.ttl !== 'number' || opts.ttl <= 0) {
|
|
181
|
+
this.logger.warn(`Invalid TTL value: ${opts.ttl}. TTL must be a positive number. Using default TTL: ${this.defaultOptions.ttl}ms`);
|
|
182
|
+
opts.ttl = this.defaultOptions.ttl;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Validate waitTimeout
|
|
186
|
+
if (opts.waitTimeout !== undefined) {
|
|
187
|
+
if (typeof opts.waitTimeout !== 'number' || opts.waitTimeout <= 0) {
|
|
188
|
+
this.logger.warn(`Invalid waitTimeout value: ${opts.waitTimeout}. waitTimeout must be a positive number. Ignoring waitTimeout.`);
|
|
189
|
+
opts.waitTimeout = undefined;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Validate retryCount
|
|
193
|
+
if (opts.retryCount !== undefined) {
|
|
194
|
+
if (typeof opts.retryCount !== 'number' || opts.retryCount < 0) {
|
|
195
|
+
this.logger.warn(`Invalid retryCount value: ${opts.retryCount}. retryCount must be a non-negative number. Using default: ${this.defaultOptions.retryCount}`);
|
|
196
|
+
opts.retryCount = this.defaultOptions.retryCount;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Validate retryDelay
|
|
200
|
+
if (opts.retryDelay !== undefined) {
|
|
201
|
+
if (typeof opts.retryDelay !== 'number' || opts.retryDelay <= 0) {
|
|
202
|
+
this.logger.warn(`Invalid retryDelay value: ${opts.retryDelay}. retryDelay must be a positive number. Using default: ${this.defaultOptions.retryDelay}ms`);
|
|
203
|
+
opts.retryDelay = this.defaultOptions.retryDelay;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Handle backward compatibility: if throwOnFailure is true, use THROW strategy
|
|
95
207
|
if (opts.throwOnFailure && !options.strategy) {
|
|
96
208
|
opts.strategy = LockStrategy.THROW;
|
|
97
209
|
}
|
|
98
210
|
const lockKey = this.buildLockKey(key, opts.keyPrefix);
|
|
99
211
|
const lockValue = this.generateLockValue();
|
|
212
|
+
// Determine max attempts based on strategy
|
|
100
213
|
let maxAttempts;
|
|
101
214
|
if (opts.strategy === LockStrategy.WAIT) {
|
|
102
|
-
maxAttempts = Number.MAX_SAFE_INTEGER;
|
|
215
|
+
maxAttempts = Number.MAX_SAFE_INTEGER; // Infinite retries for WAIT strategy
|
|
103
216
|
}
|
|
104
217
|
else {
|
|
105
218
|
maxAttempts = opts.retryCount + 1;
|
|
@@ -107,6 +220,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
107
220
|
let attempts = 0;
|
|
108
221
|
const startTime = Date.now();
|
|
109
222
|
while (attempts < maxAttempts) {
|
|
223
|
+
// Check timeout for WAIT strategy
|
|
110
224
|
if (opts.strategy === LockStrategy.WAIT && opts.waitTimeout) {
|
|
111
225
|
const elapsed = Date.now() - startTime;
|
|
112
226
|
if (elapsed >= opts.waitTimeout) {
|
|
@@ -116,9 +230,11 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
116
230
|
}
|
|
117
231
|
}
|
|
118
232
|
try {
|
|
233
|
+
// Use SET with NX (Not eXists) and PX (expiration in milliseconds)
|
|
119
234
|
const result = yield redis.set(lockKey, lockValue, 'PX', opts.ttl, 'NX');
|
|
120
235
|
if (result === 'OK') {
|
|
121
236
|
this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms, attempts: ${attempts + 1})`);
|
|
237
|
+
// Set up auto-extension if enabled
|
|
122
238
|
let autoExtendTimer;
|
|
123
239
|
if (opts.autoExtend && opts.autoExtend > 0) {
|
|
124
240
|
autoExtendTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -132,7 +248,9 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
132
248
|
}
|
|
133
249
|
return { acquired: true, lockValue, autoExtendTimer };
|
|
134
250
|
}
|
|
251
|
+
// Lock acquisition failed
|
|
135
252
|
attempts++;
|
|
253
|
+
// For WAIT strategy, log less frequently to avoid spam
|
|
136
254
|
if (opts.strategy === LockStrategy.WAIT) {
|
|
137
255
|
if (attempts === 1 || attempts % 10 === 0) {
|
|
138
256
|
this.logger.debug(`Waiting for lock ${lockKey}... (attempt ${attempts})`);
|
|
@@ -141,19 +259,47 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
141
259
|
else if (attempts < maxAttempts) {
|
|
142
260
|
this.logger.debug(`Lock acquisition failed for ${lockKey}, retrying... (${attempts}/${opts.retryCount})`);
|
|
143
261
|
}
|
|
262
|
+
// Wait before next attempt (except for last attempt)
|
|
144
263
|
if (attempts < maxAttempts) {
|
|
145
|
-
|
|
264
|
+
// Add random jitter to avoid synchronized retries
|
|
265
|
+
const jitter = opts.retryJitter ? Math.random() * opts.retryJitter : 0;
|
|
266
|
+
const totalDelay = opts.retryDelay + jitter;
|
|
267
|
+
yield this.sleep(totalDelay);
|
|
146
268
|
}
|
|
147
269
|
}
|
|
148
270
|
catch (error) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
271
|
+
// Enhanced error classification and handling
|
|
272
|
+
if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('ECONNREFUSED')) ||
|
|
273
|
+
((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes('ECONNRESET')) ||
|
|
274
|
+
error.code === 'ECONNREFUSED') {
|
|
275
|
+
// Connection error, will retry - log at debug level
|
|
276
|
+
this.logger.debug(`Redis connection error, will retry: ${error.message}`);
|
|
277
|
+
}
|
|
278
|
+
else if (((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes('READONLY')) ||
|
|
279
|
+
((_d = error.message) === null || _d === void 0 ? void 0 : _d.includes('LOADING')) ||
|
|
280
|
+
((_e = error.message) === null || _e === void 0 ? void 0 : _e.includes('MASTERDOWN'))) {
|
|
281
|
+
// Redis server error, log at warn level
|
|
282
|
+
this.logger.warn(`Redis server error: ${error.message}`);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
// Other errors, log at error level
|
|
286
|
+
const errorMessage = `Error acquiring lock for ${lockKey}: ${error.message}`;
|
|
287
|
+
this.logger.error(errorMessage, error.stack);
|
|
288
|
+
if (opts.strategy === LockStrategy.THROW) {
|
|
289
|
+
throw new Error(errorMessage);
|
|
290
|
+
}
|
|
291
|
+
return { acquired: false, error: errorMessage };
|
|
292
|
+
}
|
|
293
|
+
// For retryable errors, continue with retry logic
|
|
294
|
+
attempts++;
|
|
295
|
+
if (attempts < maxAttempts) {
|
|
296
|
+
const jitter = opts.retryJitter ? Math.random() * opts.retryJitter : 0;
|
|
297
|
+
const totalDelay = opts.retryDelay + jitter;
|
|
298
|
+
yield this.sleep(totalDelay);
|
|
153
299
|
}
|
|
154
|
-
return { acquired: false, error: errorMessage };
|
|
155
300
|
}
|
|
156
301
|
}
|
|
302
|
+
// Max attempts reached
|
|
157
303
|
const failureMessage = `Failed to acquire lock for ${lockKey} after ${attempts} attempts`;
|
|
158
304
|
this.logger.warn(failureMessage);
|
|
159
305
|
if (opts.strategy === LockStrategy.THROW) {
|
|
@@ -162,11 +308,23 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
162
308
|
return { acquired: false, error: failureMessage };
|
|
163
309
|
});
|
|
164
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Release a distributed lock
|
|
313
|
+
*
|
|
314
|
+
* Uses Lua script to ensure atomic check-and-delete operation
|
|
315
|
+
* Only releases the lock if the value matches (prevents releasing someone else's lock)
|
|
316
|
+
*
|
|
317
|
+
* @param key - Lock key
|
|
318
|
+
* @param lockValue - Lock value obtained during acquisition
|
|
319
|
+
* @param keyPrefix - Key prefix (must match acquisition)
|
|
320
|
+
* @returns True if lock was released, false otherwise
|
|
321
|
+
*/
|
|
165
322
|
releaseLock(key_1, lockValue_1) {
|
|
166
323
|
return __awaiter(this, arguments, void 0, function* (key, lockValue, keyPrefix = 'lock') {
|
|
167
324
|
const redis = yield this.getRedis();
|
|
168
325
|
const lockKey = this.buildLockKey(key, keyPrefix);
|
|
169
326
|
try {
|
|
327
|
+
// Lua script to atomically check and delete the lock
|
|
170
328
|
const script = `
|
|
171
329
|
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
172
330
|
return redis.call("del", KEYS[1])
|
|
@@ -190,11 +348,21 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
190
348
|
}
|
|
191
349
|
});
|
|
192
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Extend the expiration time of an existing lock
|
|
353
|
+
*
|
|
354
|
+
* @param key - Lock key
|
|
355
|
+
* @param lockValue - Lock value obtained during acquisition
|
|
356
|
+
* @param ttl - New TTL in milliseconds
|
|
357
|
+
* @param keyPrefix - Key prefix (must match acquisition)
|
|
358
|
+
* @returns True if lock was extended, false otherwise
|
|
359
|
+
*/
|
|
193
360
|
extendLock(key_1, lockValue_1, ttl_1) {
|
|
194
361
|
return __awaiter(this, arguments, void 0, function* (key, lockValue, ttl, keyPrefix = 'lock') {
|
|
195
362
|
const redis = yield this.getRedis();
|
|
196
363
|
const lockKey = this.buildLockKey(key, keyPrefix);
|
|
197
364
|
try {
|
|
365
|
+
// Lua script to atomically check value and extend TTL
|
|
198
366
|
const script = `
|
|
199
367
|
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
200
368
|
return redis.call("pexpire", KEYS[1], ARGV[2])
|
|
@@ -218,6 +386,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
218
386
|
}
|
|
219
387
|
});
|
|
220
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Check if a lock exists
|
|
391
|
+
*
|
|
392
|
+
* @param key - Lock key
|
|
393
|
+
* @param keyPrefix - Key prefix
|
|
394
|
+
* @returns True if lock exists, false otherwise
|
|
395
|
+
*/
|
|
221
396
|
isLocked(key_1) {
|
|
222
397
|
return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
|
|
223
398
|
const redis = yield this.getRedis();
|
|
@@ -232,6 +407,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
232
407
|
}
|
|
233
408
|
});
|
|
234
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Execute a function with automatic lock acquisition and release
|
|
412
|
+
*
|
|
413
|
+
* @param key - Lock key
|
|
414
|
+
* @param fn - Function to execute while holding the lock
|
|
415
|
+
* @param options - Lock options
|
|
416
|
+
* @returns Result of the function execution, or null if lock couldn't be acquired
|
|
417
|
+
*/
|
|
235
418
|
withLock(key_1, fn_1) {
|
|
236
419
|
return __awaiter(this, arguments, void 0, function* (key, fn, options = {}) {
|
|
237
420
|
const lockResult = yield this.acquireLock(key, options);
|
|
@@ -247,6 +430,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
247
430
|
throw error;
|
|
248
431
|
}
|
|
249
432
|
finally {
|
|
433
|
+
// Clear auto-extension timer if it exists
|
|
250
434
|
if (lockResult.autoExtendTimer) {
|
|
251
435
|
clearInterval(lockResult.autoExtendTimer);
|
|
252
436
|
}
|
|
@@ -254,6 +438,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
254
438
|
}
|
|
255
439
|
});
|
|
256
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Get lock information from Redis
|
|
443
|
+
*
|
|
444
|
+
* @param key - Lock key
|
|
445
|
+
* @param keyPrefix - Key prefix
|
|
446
|
+
* @returns Lock information including TTL and value
|
|
447
|
+
*/
|
|
257
448
|
getLockInfo(key_1) {
|
|
258
449
|
return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
|
|
259
450
|
const redis = yield this.getRedis();
|
|
@@ -274,6 +465,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
274
465
|
}
|
|
275
466
|
});
|
|
276
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Force release a lock (use with caution)
|
|
470
|
+
*
|
|
471
|
+
* @param key - Lock key
|
|
472
|
+
* @param keyPrefix - Key prefix
|
|
473
|
+
* @returns True if lock was released, false otherwise
|
|
474
|
+
*/
|
|
277
475
|
forceRelease(key_1) {
|
|
278
476
|
return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
|
|
279
477
|
const redis = yield this.getRedis();
|
|
@@ -295,19 +493,54 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
295
493
|
}
|
|
296
494
|
});
|
|
297
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Clean up locks by pattern
|
|
498
|
+
* Useful for cleaning up locks after process restart or for specific services
|
|
499
|
+
*
|
|
500
|
+
* WARNING: Use with caution in production! This will forcefully delete locks.
|
|
501
|
+
*
|
|
502
|
+
* **Note**: Uses SCAN command to avoid blocking Redis in production.
|
|
503
|
+
*
|
|
504
|
+
* @param pattern - Lock pattern (e.g., 'MyService:*' or '*:migration:*')
|
|
505
|
+
* @param keyPrefix - Key prefix (default: 'lock')
|
|
506
|
+
* @returns Number of locks deleted
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```typescript
|
|
510
|
+
* // Clean up all locks for MyService
|
|
511
|
+
* await lockService.cleanupLocksByPattern('MyService:*');
|
|
512
|
+
*
|
|
513
|
+
* // Clean up all migration locks
|
|
514
|
+
* await lockService.cleanupLocksByPattern('*:migration:*');
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
298
517
|
cleanupLocksByPattern(pattern_1) {
|
|
299
518
|
return __awaiter(this, arguments, void 0, function* (pattern, keyPrefix = 'lock') {
|
|
300
519
|
const redis = yield this.getRedis();
|
|
301
520
|
const searchPattern = `${keyPrefix}:${pattern}`;
|
|
302
521
|
try {
|
|
303
|
-
|
|
304
|
-
|
|
522
|
+
let cursor = '0';
|
|
523
|
+
const allKeys = [];
|
|
524
|
+
// Use SCAN to iterate through keys without blocking Redis
|
|
525
|
+
do {
|
|
526
|
+
const [nextCursor, keys] = yield redis.scan(cursor, 'MATCH', searchPattern, 'COUNT', 100);
|
|
527
|
+
cursor = nextCursor;
|
|
528
|
+
allKeys.push(...keys);
|
|
529
|
+
} while (cursor !== '0');
|
|
530
|
+
if (allKeys.length === 0) {
|
|
305
531
|
this.logger.debug(`No locks found matching pattern: ${searchPattern}`);
|
|
306
532
|
return 0;
|
|
307
533
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
534
|
+
// Delete keys in batches to avoid blocking Redis
|
|
535
|
+
let deletedCount = 0;
|
|
536
|
+
const batchSize = 100;
|
|
537
|
+
for (let i = 0; i < allKeys.length; i += batchSize) {
|
|
538
|
+
const batch = allKeys.slice(i, i + batchSize);
|
|
539
|
+
const result = yield redis.del(...batch);
|
|
540
|
+
deletedCount += result;
|
|
541
|
+
}
|
|
542
|
+
this.logger.log(`Cleaned up ${deletedCount} lock(s) matching pattern: ${searchPattern}`);
|
|
543
|
+
return deletedCount;
|
|
311
544
|
}
|
|
312
545
|
catch (error) {
|
|
313
546
|
this.logger.error(`Error cleaning up locks by pattern ${searchPattern}: ${error.message}`, error.stack);
|
|
@@ -315,6 +548,28 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
315
548
|
}
|
|
316
549
|
});
|
|
317
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Clean up locks on startup
|
|
553
|
+
* This method is useful for cleaning up stale locks from previous process instances
|
|
554
|
+
*
|
|
555
|
+
* WARNING: Only use this if you're sure the locks are from previous process instances!
|
|
556
|
+
*
|
|
557
|
+
* @param patterns - Array of lock patterns to clean up
|
|
558
|
+
* @param keyPrefix - Key prefix (default: 'lock')
|
|
559
|
+
* @returns Total number of locks deleted
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* // In your module's onModuleInit
|
|
564
|
+
* async onModuleInit() {
|
|
565
|
+
* // Clean up locks from this service that might be left from previous restart
|
|
566
|
+
* await this.lockService.cleanupOnStartup([
|
|
567
|
+
* 'MyService:*',
|
|
568
|
+
* 'AnotherService:*'
|
|
569
|
+
* ]);
|
|
570
|
+
* }
|
|
571
|
+
* ```
|
|
572
|
+
*/
|
|
318
573
|
cleanupOnStartup(patterns_1) {
|
|
319
574
|
return __awaiter(this, arguments, void 0, function* (patterns, keyPrefix = 'lock') {
|
|
320
575
|
this.logger.log(`Starting lock cleanup for ${patterns.length} pattern(s) on startup...`);
|
|
@@ -327,10 +582,17 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
327
582
|
return totalDeleted;
|
|
328
583
|
});
|
|
329
584
|
}
|
|
585
|
+
/**
|
|
586
|
+
* Health check for Redis connection
|
|
587
|
+
* Returns information about Redis connectivity and lock service status
|
|
588
|
+
*
|
|
589
|
+
* @returns Health check result
|
|
590
|
+
*/
|
|
330
591
|
healthCheck() {
|
|
331
592
|
return __awaiter(this, void 0, void 0, function* () {
|
|
332
593
|
try {
|
|
333
594
|
const redis = yield this.getRedis();
|
|
595
|
+
// Try to ping Redis
|
|
334
596
|
const pong = yield redis.ping();
|
|
335
597
|
if (pong === 'PONG') {
|
|
336
598
|
return {
|
|
@@ -356,20 +618,38 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
356
618
|
}
|
|
357
619
|
});
|
|
358
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Get all active locks with optional pattern filtering
|
|
623
|
+
* Useful for monitoring and debugging
|
|
624
|
+
*
|
|
625
|
+
* **Note**: Uses SCAN command to avoid blocking Redis in production.
|
|
626
|
+
*
|
|
627
|
+
* @param pattern - Optional pattern to filter locks (e.g., 'MyService:*')
|
|
628
|
+
* @param keyPrefix - Key prefix (default: 'lock')
|
|
629
|
+
* @returns Array of active lock information
|
|
630
|
+
*/
|
|
359
631
|
getActiveLocks() {
|
|
360
632
|
return __awaiter(this, arguments, void 0, function* (pattern = '*', keyPrefix = 'lock') {
|
|
361
633
|
const redis = yield this.getRedis();
|
|
362
634
|
const searchPattern = `${keyPrefix}:${pattern}`;
|
|
363
635
|
try {
|
|
364
|
-
|
|
365
|
-
|
|
636
|
+
let cursor = '0';
|
|
637
|
+
const allKeys = [];
|
|
638
|
+
// Use SCAN to iterate through keys without blocking Redis
|
|
639
|
+
do {
|
|
640
|
+
const [nextCursor, keys] = yield redis.scan(cursor, 'MATCH', searchPattern, 'COUNT', 100);
|
|
641
|
+
cursor = nextCursor;
|
|
642
|
+
allKeys.push(...keys);
|
|
643
|
+
} while (cursor !== '0');
|
|
644
|
+
if (allKeys.length === 0) {
|
|
366
645
|
return [];
|
|
367
646
|
}
|
|
368
|
-
const locks = yield Promise.all(
|
|
647
|
+
const locks = yield Promise.all(allKeys.map((key) => __awaiter(this, void 0, void 0, function* () {
|
|
369
648
|
const [value, ttl] = yield Promise.all([
|
|
370
649
|
redis.get(key),
|
|
371
650
|
redis.pttl(key),
|
|
372
651
|
]);
|
|
652
|
+
// Remove the key prefix for cleaner output
|
|
373
653
|
const cleanKey = key.startsWith(`${keyPrefix}:`)
|
|
374
654
|
? key.substring(`${keyPrefix}:`.length)
|
|
375
655
|
: key;
|
|
@@ -387,6 +667,10 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
387
667
|
}
|
|
388
668
|
});
|
|
389
669
|
}
|
|
670
|
+
/**
|
|
671
|
+
* Get Redis connection
|
|
672
|
+
* Requires external Redis client to be set
|
|
673
|
+
*/
|
|
390
674
|
getRedis() {
|
|
391
675
|
return __awaiter(this, void 0, void 0, function* () {
|
|
392
676
|
if (!this.redis) {
|
|
@@ -395,12 +679,51 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
395
679
|
return this.redis;
|
|
396
680
|
});
|
|
397
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Generate a unique lock value
|
|
684
|
+
* Format: instanceId:timestamp:random:pid
|
|
685
|
+
*
|
|
686
|
+
* @returns Unique lock identifier
|
|
687
|
+
*/
|
|
398
688
|
generateLockValue() {
|
|
399
|
-
|
|
689
|
+
const timestamp = Date.now();
|
|
690
|
+
const random = Math.random().toString(36).substring(2, 15);
|
|
691
|
+
const pid = process.pid;
|
|
692
|
+
return `${this.instanceId}:${timestamp}:${random}:${pid}`;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Get instance identifier
|
|
696
|
+
* Used to distinguish different process instances in distributed environments
|
|
697
|
+
*
|
|
698
|
+
* @returns Instance identifier
|
|
699
|
+
*/
|
|
700
|
+
getInstanceId() {
|
|
701
|
+
// 1. Kubernetes Pod name
|
|
702
|
+
if (process.env.HOSTNAME) {
|
|
703
|
+
return process.env.HOSTNAME;
|
|
704
|
+
}
|
|
705
|
+
// 2. Custom instance ID
|
|
706
|
+
if (process.env.INSTANCE_ID) {
|
|
707
|
+
return process.env.INSTANCE_ID;
|
|
708
|
+
}
|
|
709
|
+
// 3. Generate unique ID
|
|
710
|
+
return `instance-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
400
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
* Build the full Redis key for a lock
|
|
714
|
+
*
|
|
715
|
+
* @param key - Lock key
|
|
716
|
+
* @param prefix - Key prefix
|
|
717
|
+
* @returns Full Redis key
|
|
718
|
+
*/
|
|
401
719
|
buildLockKey(key, prefix = 'lock') {
|
|
402
720
|
return `${prefix}:${key}`;
|
|
403
721
|
}
|
|
722
|
+
/**
|
|
723
|
+
* Sleep for a specified duration
|
|
724
|
+
*
|
|
725
|
+
* @param ms - Milliseconds to sleep
|
|
726
|
+
*/
|
|
404
727
|
sleep(ms) {
|
|
405
728
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
406
729
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import '../common/boilerplate.polyfill';
|
|
1
2
|
import type { NestExpressApplication } from '@nestjs/platform-express';
|
|
2
3
|
export declare function bootstrapSetup(AppModule: any, SetupSwagger: any): Promise<NestExpressApplication<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>>;
|