@nest-omni/core 4.1.3-3 → 4.1.3-30
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 +1 -0
- package/audit/audit.module.js +51 -2
- package/audit/controllers/audit.controller.d.ts +57 -1
- package/audit/controllers/audit.controller.js +43 -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 +1 -1
- package/audit/decorators/audit-controller.decorator.js +2 -2
- package/audit/decorators/audit-operation.decorator.d.ts +0 -7
- package/audit/decorators/audit-operation.decorator.js +0 -7
- package/audit/decorators/entity-audit.decorator.d.ts +78 -2
- package/audit/decorators/entity-audit.decorator.js +145 -4
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +2 -0
- package/audit/dto/audit-action-query.dto.d.ts +13 -0
- package/audit/dto/audit-action-query.dto.js +77 -0
- package/audit/dto/index.d.ts +1 -0
- package/audit/dto/index.js +1 -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 +7 -2
- package/audit/entities/entity-audit-log.entity.js +45 -9
- package/audit/entities/entity-transaction.entity.d.ts +8 -2
- package/audit/entities/entity-transaction.entity.js +39 -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 +0 -2
- package/audit/entities/manual-operation-log.entity.js +8 -9
- package/audit/enums/audit.enums.d.ts +14 -6
- package/audit/enums/audit.enums.js +18 -9
- package/audit/examples/decorator-value-mapping.example.d.ts +70 -0
- package/audit/examples/decorator-value-mapping.example.js +414 -0
- package/audit/index.d.ts +5 -1
- package/audit/index.js +29 -2
- package/audit/interceptors/audit-action.interceptor.d.ts +39 -0
- package/audit/interceptors/audit-action.interceptor.js +217 -0
- package/audit/interceptors/audit.interceptor.d.ts +1 -0
- package/audit/interceptors/audit.interceptor.js +19 -11
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +132 -4
- package/audit/services/audit-action.service.d.ts +142 -0
- package/audit/services/audit-action.service.js +246 -0
- package/audit/services/audit-context.service.d.ts +91 -0
- package/audit/services/audit-context.service.js +170 -0
- package/audit/services/entity-audit.service.d.ts +220 -9
- package/audit/services/entity-audit.service.js +761 -72
- package/audit/services/index.d.ts +3 -0
- package/audit/services/index.js +3 -0
- package/audit/services/manual-audit-log.service.d.ts +23 -23
- package/audit/services/manual-audit-log.service.js +34 -57
- package/audit/services/multi-database.service.d.ts +0 -5
- package/audit/services/multi-database.service.js +0 -24
- package/audit/services/operation-description.service.d.ts +14 -3
- package/audit/services/operation-description.service.js +165 -26
- package/audit/services/transaction-audit.service.d.ts +1 -0
- package/audit/services/transaction-audit.service.js +12 -9
- package/audit/subscribers/entity-audit.subscriber.d.ts +5 -0
- package/audit/subscribers/entity-audit.subscriber.js +69 -5
- package/cache/cache.module.d.ts +7 -8
- package/cache/cache.module.js +15 -13
- package/cache/cache.service.d.ts +6 -4
- package/cache/cache.service.js +24 -12
- package/cache/decorators/cache-put.decorator.js +5 -4
- package/cache/dependencies/callback.dependency.js +9 -0
- package/cache/dependencies/db.dependency.d.ts +43 -12
- package/cache/dependencies/db.dependency.js +46 -18
- package/cache/dependencies/tag.dependency.d.ts +31 -4
- package/cache/dependencies/tag.dependency.js +100 -11
- package/cache/entities/index.d.ts +1 -0
- package/cache/entities/index.js +17 -0
- package/cache/entities/typeorm-cache.entity.d.ts +71 -0
- package/cache/entities/typeorm-cache.entity.js +110 -0
- package/cache/index.d.ts +2 -1
- package/cache/index.js +19 -2
- package/cache/interfaces/cache-options.interface.d.ts +8 -0
- package/cache/providers/index.d.ts +2 -1
- package/cache/providers/index.js +2 -1
- package/cache/providers/lrucache.provider.d.ts +77 -0
- package/cache/providers/lrucache.provider.js +228 -0
- package/cache/providers/redis-cache.provider.d.ts +1 -0
- package/cache/providers/redis-cache.provider.js +8 -6
- package/cache/providers/typeorm-cache.provider.d.ts +211 -0
- package/cache/providers/typeorm-cache.provider.js +483 -0
- package/common/boilerplate.polyfill.d.ts +1 -0
- package/common/boilerplate.polyfill.js +18 -1
- package/common/helpers/validation-metadata-helper.d.ts +112 -0
- package/common/helpers/validation-metadata-helper.js +164 -0
- package/common/index.d.ts +1 -0
- package/common/index.js +4 -0
- package/decorators/examples/field-i18n.example.d.ts +294 -0
- package/decorators/examples/field-i18n.example.js +478 -0
- package/decorators/field.decorators.d.ts +95 -3
- package/decorators/field.decorators.js +152 -18
- package/decorators/transform.decorators.d.ts +0 -2
- package/decorators/transform.decorators.js +0 -23
- package/decorators/translate.decorator.d.ts +26 -0
- package/decorators/translate.decorator.js +26 -1
- package/email-log/email-log.constants.d.ts +8 -0
- package/email-log/email-log.constants.js +11 -0
- package/email-log/email-log.module.d.ts +47 -0
- package/email-log/email-log.module.js +140 -0
- package/email-log/index.d.ts +11 -0
- package/email-log/index.js +48 -0
- package/email-log/interfaces/email-log-options.interface.d.ts +61 -0
- package/email-log/interfaces/email-log-options.interface.js +134 -0
- package/email-log/interfaces/email-log-transport.interface.d.ts +20 -0
- package/email-log/interfaces/email-log-transport.interface.js +2 -0
- package/email-log/interfaces/index.d.ts +2 -0
- package/email-log/interfaces/index.js +18 -0
- package/email-log/providers/email-provider.d.ts +42 -0
- package/email-log/providers/email-provider.js +127 -0
- package/email-log/providers/index.d.ts +1 -0
- package/email-log/providers/index.js +17 -0
- package/email-log/services/email-log-alert.service.d.ts +46 -0
- package/email-log/services/email-log-alert.service.js +162 -0
- package/email-log/services/email-log-formatter.service.d.ts +78 -0
- package/email-log/services/email-log-formatter.service.js +442 -0
- package/email-log/services/email-log-logger.service.d.ts +85 -0
- package/email-log/services/email-log-logger.service.js +168 -0
- package/email-log/services/email-log-rate-limiter.service.d.ts +42 -0
- package/email-log/services/email-log-rate-limiter.service.js +110 -0
- package/email-log/services/email-log-transport.service.d.ts +80 -0
- package/email-log/services/email-log-transport.service.js +271 -0
- package/email-log/services/index.d.ts +5 -0
- package/email-log/services/index.js +21 -0
- package/email-log/transports/index.d.ts +1 -0
- package/email-log/transports/index.js +17 -0
- package/email-log/transports/pino-email.transport.d.ts +56 -0
- package/email-log/transports/pino-email.transport.js +188 -0
- package/email-log/utils/index.d.ts +2 -0
- package/email-log/utils/index.js +18 -0
- package/email-log/utils/log-level.helper.d.ts +46 -0
- package/email-log/utils/log-level.helper.js +74 -0
- package/email-log/utils/pino-transport.utils.d.ts +135 -0
- package/email-log/utils/pino-transport.utils.js +238 -0
- 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/bad-request.filter.d.ts +9 -0
- package/filters/bad-request.filter.js +57 -16
- package/http-client/config/http-client.config.d.ts +5 -0
- package/http-client/config/http-client.config.js +27 -14
- package/http-client/decorators/http-client.decorators.d.ts +7 -28
- package/http-client/decorators/http-client.decorators.js +124 -99
- package/http-client/entities/http-log.entity.d.ts +0 -20
- package/http-client/entities/http-log.entity.js +1 -21
- package/http-client/examples/advanced-usage.example.d.ts +4 -5
- package/http-client/examples/advanced-usage.example.js +7 -59
- package/http-client/examples/axios-config-extended.example.d.ts +17 -0
- package/http-client/examples/axios-config-extended.example.js +311 -0
- package/http-client/examples/flexible-response-example.d.ts +28 -0
- package/http-client/examples/flexible-response-example.js +120 -0
- package/http-client/examples/index.d.ts +2 -0
- package/http-client/examples/index.js +2 -0
- 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/examples/ssl-certificate.example.d.ts +47 -0
- package/http-client/examples/ssl-certificate.example.js +432 -0
- package/http-client/http-client.module.d.ts +43 -2
- package/http-client/http-client.module.js +150 -90
- package/http-client/index.d.ts +1 -1
- package/http-client/interfaces/api-client-config.interface.d.ts +24 -103
- package/http-client/interfaces/http-client-config.interface.d.ts +137 -62
- package/http-client/services/api-client-registry.service.d.ts +8 -21
- package/http-client/services/api-client-registry.service.js +31 -282
- package/http-client/services/circuit-breaker.service.d.ts +69 -2
- package/http-client/services/circuit-breaker.service.js +185 -7
- package/http-client/services/http-client.service.d.ts +85 -23
- package/http-client/services/http-client.service.js +512 -168
- package/http-client/services/http-log-query.service.js +0 -13
- package/http-client/services/index.d.ts +0 -1
- package/http-client/services/index.js +0 -1
- package/http-client/services/logging.service.d.ts +69 -16
- package/http-client/services/logging.service.js +290 -170
- package/http-client/utils/call-stack-extractor.util.d.ts +26 -0
- package/http-client/utils/call-stack-extractor.util.js +35 -0
- package/http-client/utils/context-extractor.util.d.ts +2 -0
- package/http-client/utils/context-extractor.util.js +17 -3
- package/http-client/utils/curl-generator.util.js +2 -5
- package/http-client/utils/index.d.ts +2 -0
- package/http-client/utils/index.js +2 -0
- package/http-client/utils/proxy-environment.util.d.ts +42 -0
- package/http-client/utils/proxy-environment.util.js +154 -0
- package/http-client/utils/retry-recorder.util.d.ts +0 -4
- package/http-client/utils/retry-recorder.util.js +2 -27
- package/http-client/utils/sanitize.util.d.ts +58 -0
- package/http-client/utils/sanitize.util.js +188 -0
- package/http-client/utils/security-validator.util.d.ts +118 -0
- package/http-client/utils/security-validator.util.js +354 -0
- package/index.d.ts +4 -1
- package/index.js +6 -1
- package/interceptors/translation-interceptor.service.d.ts +7 -0
- package/interceptors/translation-interceptor.service.js +40 -8
- package/ip-filter/constants.d.ts +21 -0
- package/ip-filter/constants.js +24 -0
- package/ip-filter/decorators/index.d.ts +1 -0
- package/ip-filter/decorators/index.js +17 -0
- package/ip-filter/decorators/ip-filter.decorator.d.ts +58 -0
- package/ip-filter/decorators/ip-filter.decorator.js +79 -0
- package/ip-filter/guards/index.d.ts +1 -0
- package/ip-filter/guards/index.js +17 -0
- package/ip-filter/guards/ip-filter.guard.d.ts +62 -0
- package/ip-filter/guards/ip-filter.guard.js +174 -0
- package/ip-filter/index.d.ts +7 -0
- package/ip-filter/index.js +23 -0
- package/ip-filter/interfaces/index.d.ts +4 -0
- package/ip-filter/interfaces/index.js +20 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.d.ts +15 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.d.ts +26 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-options.interface.d.ts +34 -0
- package/ip-filter/interfaces/ip-filter-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-rule.interface.d.ts +36 -0
- package/ip-filter/interfaces/ip-rule.interface.js +2 -0
- package/ip-filter/ip-filter.module.d.ts +55 -0
- package/ip-filter/ip-filter.module.js +105 -0
- package/ip-filter/services/index.d.ts +1 -0
- package/ip-filter/services/index.js +17 -0
- package/ip-filter/services/ip-filter.service.d.ts +92 -0
- package/ip-filter/services/ip-filter.service.js +238 -0
- package/ip-filter/utils/index.d.ts +1 -0
- package/ip-filter/utils/index.js +17 -0
- package/ip-filter/utils/ip-utils.d.ts +61 -0
- package/ip-filter/utils/ip-utils.js +162 -0
- package/package.json +34 -29
- package/providers/context.provider.d.ts +9 -0
- package/providers/context.provider.js +13 -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/index.d.ts +2 -0
- package/redis-lock/index.js +5 -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.module.d.ts +6 -0
- package/redis-lock/redis-lock.module.js +136 -77
- package/redis-lock/redis-lock.service.d.ts +31 -0
- package/redis-lock/redis-lock.service.js +124 -17
- package/setup/bootstrap.setup.d.ts +2 -1
- package/setup/bootstrap.setup.js +3 -2
- package/setup/index.d.ts +1 -0
- package/setup/index.js +1 -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 +1 -0
- package/setup/schedule.decorator.js +28 -13
- package/setup/worker.decorator.js +10 -1
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +28 -17
- package/shared/services/api-config.service.d.ts +41 -0
- package/shared/services/api-config.service.js +166 -8
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/validators/custom-validate.validator.d.ts +1 -0
- package/validators/custom-validate.validator.js +1 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/is-exists.validator.d.ts +15 -6
- package/validators/is-exists.validator.js +8 -7
- package/validators/is-unique.validator.d.ts +22 -7
- package/validators/is-unique.validator.js +41 -17
- package/vault/vault-config.service.js +1 -1
- package/cache/providers/memory-cache.provider.d.ts +0 -49
- package/cache/providers/memory-cache.provider.js +0 -197
- package/http-client/services/cache.service.d.ts +0 -76
- package/http-client/services/cache.service.js +0 -333
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nest-omni/core",
|
|
3
|
-
"version": "4.1.3-
|
|
3
|
+
"version": "4.1.3-30",
|
|
4
4
|
"description": "A comprehensive NestJS framework for building enterprise-grade applications with best practices",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -36,67 +36,72 @@
|
|
|
36
36
|
"author": "Jinpy",
|
|
37
37
|
"license": "Apache-2.0",
|
|
38
38
|
"engines": {
|
|
39
|
-
"node": ">=
|
|
39
|
+
"node": ">=22.0.0",
|
|
40
40
|
"npm": ">=9.0.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/compression": "^1.8.1",
|
|
44
|
-
"@types/express": "^5.0.
|
|
44
|
+
"@types/express": "^5.0.6",
|
|
45
45
|
"@types/express-session": "^1.18.2",
|
|
46
|
-
"@types/lodash": "^4.17.
|
|
47
|
-
"@types/node": "^
|
|
46
|
+
"@types/lodash": "^4.17.21",
|
|
47
|
+
"@types/node": "^25.0.3",
|
|
48
|
+
"@types/nodemailer": "^6.4.17",
|
|
49
|
+
"@types/sharp": "^0.32.0",
|
|
48
50
|
"@types/sprintf-js": "^1.1.4",
|
|
49
51
|
"@types/uuid": "^11.0.0",
|
|
52
|
+
"sqlite3": "^5.1.7",
|
|
50
53
|
"typescript": "^5.9.3"
|
|
51
54
|
},
|
|
52
55
|
"dependencies": {
|
|
53
56
|
"@dataui/crud": "^5.3.4",
|
|
54
57
|
"@dataui/crud-typeorm": "^5.3.4",
|
|
55
|
-
"@
|
|
56
|
-
"@nestjs-cls/transactional-adapter-typeorm": "^1.3.0",
|
|
58
|
+
"@nest-omni/transaction": "*",
|
|
57
59
|
"@nestjs/bull": "^11.0.4",
|
|
58
|
-
"@nestjs/common": "^11.1.
|
|
60
|
+
"@nestjs/common": "^11.1.11",
|
|
59
61
|
"@nestjs/config": "^4.0.2",
|
|
60
|
-
"@nestjs/core": "^11.1.
|
|
61
|
-
"@nestjs/platform-express": "^11.1.
|
|
62
|
-
"@nestjs/schedule": "^6.0
|
|
63
|
-
"@nestjs/swagger": "^11.2.
|
|
62
|
+
"@nestjs/core": "^11.1.11",
|
|
63
|
+
"@nestjs/platform-express": "^11.1.11",
|
|
64
|
+
"@nestjs/schedule": "^6.1.0",
|
|
65
|
+
"@nestjs/swagger": "^11.2.4",
|
|
64
66
|
"@nestjs/terminus": "^11.0.0",
|
|
65
67
|
"@nestjs/typeorm": "^11.0.0",
|
|
66
|
-
"@sentry/nestjs": "^10.
|
|
67
|
-
"@sentry/profiling-node": "^10.
|
|
68
|
+
"@sentry/nestjs": "^10.32.1",
|
|
69
|
+
"@sentry/profiling-node": "^10.32.1",
|
|
68
70
|
"@songkeys/nestjs-redis": "^11.0.0",
|
|
69
71
|
"@songkeys/nestjs-redis-health": "^11.0.0",
|
|
70
|
-
"axios": "^1.
|
|
72
|
+
"axios": "^1.13.2",
|
|
71
73
|
"axios-retry": "^4.5.0",
|
|
72
74
|
"bcrypt": "^6.0.0",
|
|
73
|
-
"body-parser": "^2.2.
|
|
75
|
+
"body-parser": "^2.2.1",
|
|
74
76
|
"bull": "^4.16.5",
|
|
75
77
|
"class-transformer": "^0.5.1",
|
|
76
|
-
"class-validator": "^0.14.
|
|
78
|
+
"class-validator": "^0.14.3",
|
|
77
79
|
"compression": "^1.8.1",
|
|
78
80
|
"connect-redis": "^9.0.0",
|
|
79
81
|
"dotenv": "^17.2.3",
|
|
80
|
-
"express": "^5.1
|
|
82
|
+
"express": "^5.2.1",
|
|
81
83
|
"express-session": "^1.18.2",
|
|
84
|
+
"fast-csv": "^5.0.5",
|
|
82
85
|
"hygen": "^6.2.11",
|
|
83
|
-
"ioredis": "^5.
|
|
84
|
-
"libphonenumber-js": "^1.12.25",
|
|
86
|
+
"ioredis": "^5.9.0",
|
|
85
87
|
"lodash": "^4.17.21",
|
|
86
|
-
"mime-types": "^3.0.
|
|
88
|
+
"mime-types": "^3.0.2",
|
|
87
89
|
"moment": "^2.30.1",
|
|
88
|
-
"mysql2": "^3.
|
|
89
|
-
"nestjs-cls": "^6.0
|
|
90
|
-
"
|
|
91
|
-
"nestjs-
|
|
90
|
+
"mysql2": "^3.16.0",
|
|
91
|
+
"nestjs-cls": "^6.2.0",
|
|
92
|
+
"nodemailer": "^6.9.16",
|
|
93
|
+
"nestjs-i18n": "^10.6.0",
|
|
94
|
+
"nestjs-pino": "^4.5.0",
|
|
95
|
+
"node-vault": "^0.10.9",
|
|
92
96
|
"pino-http": "^11.0.0",
|
|
93
|
-
"pino-pretty": "^13.1.
|
|
97
|
+
"pino-pretty": "^13.1.3",
|
|
94
98
|
"reflect-metadata": "^0.2.2",
|
|
95
99
|
"rxjs": "^7.8.2",
|
|
96
100
|
"source-map-support": "^0.5.21",
|
|
97
101
|
"sprintf-js": "^1.1.3",
|
|
98
|
-
"typeorm": "^0.3.
|
|
102
|
+
"typeorm": "^0.3.28",
|
|
99
103
|
"uuid": "^13.0.0",
|
|
100
|
-
"
|
|
101
|
-
}
|
|
104
|
+
"xlsx": "git+https://git.sheetjs.com/sheetjs/sheetjs.git#v0.20.3"
|
|
105
|
+
},
|
|
106
|
+
"peerDependencies": {}
|
|
102
107
|
}
|
|
@@ -3,6 +3,7 @@ export declare class ContextProvider {
|
|
|
3
3
|
private static readonly nameSpace;
|
|
4
4
|
private static readonly authUserKey;
|
|
5
5
|
private static readonly routerKey;
|
|
6
|
+
private static readonly sourceKey;
|
|
6
7
|
private static readonly languageKey;
|
|
7
8
|
private static readonly requestKey;
|
|
8
9
|
static get<T>(key: string): import("nestjs-cls/dist/src/types/type-if-type.type").TypeIfUndefined<T, import("nestjs-cls").ClsStore, T>;
|
|
@@ -31,4 +32,12 @@ export declare class ContextProvider {
|
|
|
31
32
|
static getRole(): string;
|
|
32
33
|
static getAdmin(): boolean;
|
|
33
34
|
static getTenantId(): string;
|
|
35
|
+
/**
|
|
36
|
+
* 设置请求来源(如业务主键ID等)
|
|
37
|
+
*/
|
|
38
|
+
static setSource(source: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* 获取请求来源
|
|
41
|
+
*/
|
|
42
|
+
static getSource(): string | undefined;
|
|
34
43
|
}
|
|
@@ -73,10 +73,23 @@ class ContextProvider {
|
|
|
73
73
|
static getTenantId() {
|
|
74
74
|
return ContextProvider.getAuthUserField('tenantId');
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* 设置请求来源(如业务主键ID等)
|
|
78
|
+
*/
|
|
79
|
+
static setSource(source) {
|
|
80
|
+
ContextProvider.set(ContextProvider.sourceKey, source);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 获取请求来源
|
|
84
|
+
*/
|
|
85
|
+
static getSource() {
|
|
86
|
+
return ContextProvider.get(ContextProvider.sourceKey);
|
|
87
|
+
}
|
|
76
88
|
}
|
|
77
89
|
exports.ContextProvider = ContextProvider;
|
|
78
90
|
ContextProvider.nameSpace = 'request';
|
|
79
91
|
ContextProvider.authUserKey = 'user_key';
|
|
80
92
|
ContextProvider.routerKey = 'router_key';
|
|
93
|
+
ContextProvider.sourceKey = 'source_key';
|
|
81
94
|
ContextProvider.languageKey = 'language_key';
|
|
82
95
|
ContextProvider.requestKey = 'request_key';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { OnModuleInit, OnApplicationShutdown } from '@nestjs/common';
|
|
2
|
+
import { RedisLockService } from './redis-lock.service';
|
|
3
|
+
import { LockHeartbeatService } from './lock-heartbeat.service';
|
|
4
|
+
/**
|
|
5
|
+
* Comprehensive lock cleanup service
|
|
6
|
+
*
|
|
7
|
+
* Provides safe and comprehensive lock cleanup mechanism for distributed environments.
|
|
8
|
+
* Combines instance-based precise cleanup with heartbeat-based dead instance detection.
|
|
9
|
+
*
|
|
10
|
+
* **Cleanup Strategy:**
|
|
11
|
+
* 1. **Immediate Precise Cleanup (0s):**
|
|
12
|
+
* - Only cleans locks from the current instance
|
|
13
|
+
* - Safe during rolling updates - won't affect other running instances
|
|
14
|
+
*
|
|
15
|
+
* 2. **Delayed Conservative Cleanup (60s):**
|
|
16
|
+
* - Checks heartbeat of other instances
|
|
17
|
+
* - Only cleans locks from dead instances (no heartbeat)
|
|
18
|
+
* - Gives enough time for rolling updates to complete
|
|
19
|
+
*
|
|
20
|
+
* 3. **Graceful Shutdown Cleanup:**
|
|
21
|
+
* - On SIGTERM/SIGINT, immediately cleans own locks
|
|
22
|
+
* - Ensures locks are released before process exits
|
|
23
|
+
* - Works with PM2 reload and Kubernetes rolling updates
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // In your module
|
|
28
|
+
* @Module({
|
|
29
|
+
* providers: [
|
|
30
|
+
* RedisLockService,
|
|
31
|
+
* LockHeartbeatService,
|
|
32
|
+
* ComprehensiveLockCleanupService,
|
|
33
|
+
* ],
|
|
34
|
+
* })
|
|
35
|
+
* export class AppModule {}
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class ComprehensiveLockCleanupService implements OnModuleInit, OnApplicationShutdown {
|
|
39
|
+
private readonly lockService;
|
|
40
|
+
private readonly heartbeatService;
|
|
41
|
+
private readonly logger;
|
|
42
|
+
private readonly instanceId;
|
|
43
|
+
/**
|
|
44
|
+
* Grace period before cleaning other instances' locks (milliseconds)
|
|
45
|
+
* @default 60000 (60 seconds)
|
|
46
|
+
*/
|
|
47
|
+
private readonly gracePeriod;
|
|
48
|
+
constructor(lockService: RedisLockService, heartbeatService: LockHeartbeatService);
|
|
49
|
+
onModuleInit(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Clean up locks from the current instance
|
|
52
|
+
* Safe to run immediately - only affects locks created by this instance
|
|
53
|
+
*/
|
|
54
|
+
private cleanupOwnLocks;
|
|
55
|
+
/**
|
|
56
|
+
* Clean up locks from dead instances
|
|
57
|
+
* Only runs after grace period to avoid cleaning locks during rolling updates
|
|
58
|
+
*/
|
|
59
|
+
private cleanupDeadInstanceLocks;
|
|
60
|
+
/**
|
|
61
|
+
* Check if a lock belongs to the current instance
|
|
62
|
+
*
|
|
63
|
+
* @param lockValue - Lock value to check
|
|
64
|
+
* @returns True if lock belongs to current instance
|
|
65
|
+
*/
|
|
66
|
+
private isOwnLock;
|
|
67
|
+
/**
|
|
68
|
+
* Extract instance ID from lock value
|
|
69
|
+
* Lock value format: instanceId:timestamp:random:pid
|
|
70
|
+
*
|
|
71
|
+
* @param lockValue - Lock value
|
|
72
|
+
* @returns Instance ID or null if cannot be extracted
|
|
73
|
+
*/
|
|
74
|
+
private extractInstanceId;
|
|
75
|
+
/**
|
|
76
|
+
* Get instance identifier
|
|
77
|
+
*/
|
|
78
|
+
private getInstanceId;
|
|
79
|
+
/**
|
|
80
|
+
* Manually trigger cleanup of all stale locks
|
|
81
|
+
* Use with caution - this will clean both own and dead instance locks
|
|
82
|
+
*/
|
|
83
|
+
manualCleanup(): Promise<{
|
|
84
|
+
ownLocks: number;
|
|
85
|
+
deadLocks: number;
|
|
86
|
+
}>;
|
|
87
|
+
private cleanupOwnLocksCount;
|
|
88
|
+
private cleanupDeadInstanceLocksCount;
|
|
89
|
+
/**
|
|
90
|
+
* Cleanup own locks on application shutdown
|
|
91
|
+
* Called when receiving SIGTERM/SIGINT (graceful shutdown)
|
|
92
|
+
*/
|
|
93
|
+
onApplicationShutdown(signal?: string): Promise<void>;
|
|
94
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
var ComprehensiveLockCleanupService_1;
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.ComprehensiveLockCleanupService = void 0;
|
|
23
|
+
const common_1 = require("@nestjs/common");
|
|
24
|
+
const redis_lock_service_1 = require("./redis-lock.service");
|
|
25
|
+
const lock_heartbeat_service_1 = require("./lock-heartbeat.service");
|
|
26
|
+
/**
|
|
27
|
+
* Comprehensive lock cleanup service
|
|
28
|
+
*
|
|
29
|
+
* Provides safe and comprehensive lock cleanup mechanism for distributed environments.
|
|
30
|
+
* Combines instance-based precise cleanup with heartbeat-based dead instance detection.
|
|
31
|
+
*
|
|
32
|
+
* **Cleanup Strategy:**
|
|
33
|
+
* 1. **Immediate Precise Cleanup (0s):**
|
|
34
|
+
* - Only cleans locks from the current instance
|
|
35
|
+
* - Safe during rolling updates - won't affect other running instances
|
|
36
|
+
*
|
|
37
|
+
* 2. **Delayed Conservative Cleanup (60s):**
|
|
38
|
+
* - Checks heartbeat of other instances
|
|
39
|
+
* - Only cleans locks from dead instances (no heartbeat)
|
|
40
|
+
* - Gives enough time for rolling updates to complete
|
|
41
|
+
*
|
|
42
|
+
* 3. **Graceful Shutdown Cleanup:**
|
|
43
|
+
* - On SIGTERM/SIGINT, immediately cleans own locks
|
|
44
|
+
* - Ensures locks are released before process exits
|
|
45
|
+
* - Works with PM2 reload and Kubernetes rolling updates
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // In your module
|
|
50
|
+
* @Module({
|
|
51
|
+
* providers: [
|
|
52
|
+
* RedisLockService,
|
|
53
|
+
* LockHeartbeatService,
|
|
54
|
+
* ComprehensiveLockCleanupService,
|
|
55
|
+
* ],
|
|
56
|
+
* })
|
|
57
|
+
* export class AppModule {}
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
let ComprehensiveLockCleanupService = ComprehensiveLockCleanupService_1 = class ComprehensiveLockCleanupService {
|
|
61
|
+
constructor(lockService, heartbeatService) {
|
|
62
|
+
this.lockService = lockService;
|
|
63
|
+
this.heartbeatService = heartbeatService;
|
|
64
|
+
this.logger = new common_1.Logger(ComprehensiveLockCleanupService_1.name);
|
|
65
|
+
/**
|
|
66
|
+
* Grace period before cleaning other instances' locks (milliseconds)
|
|
67
|
+
* @default 60000 (60 seconds)
|
|
68
|
+
*/
|
|
69
|
+
this.gracePeriod = 60000;
|
|
70
|
+
this.instanceId = this.getInstanceId();
|
|
71
|
+
}
|
|
72
|
+
onModuleInit() {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
this.logger.log('Starting comprehensive lock cleanup...');
|
|
75
|
+
// Step 1: Immediate precise cleanup - only clean own instance's locks
|
|
76
|
+
yield this.cleanupOwnLocks();
|
|
77
|
+
// Step 2: Delayed cleanup - clean dead instances' locks after grace period
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
this.cleanupDeadInstanceLocks().catch((error) => {
|
|
80
|
+
this.logger.error('Failed to cleanup dead instance locks:', error);
|
|
81
|
+
});
|
|
82
|
+
}, this.gracePeriod);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clean up locks from the current instance
|
|
87
|
+
* Safe to run immediately - only affects locks created by this instance
|
|
88
|
+
*/
|
|
89
|
+
cleanupOwnLocks() {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
this.logger.log(`Cleaning locks for this instance: ${this.instanceId}`);
|
|
92
|
+
try {
|
|
93
|
+
const allLocks = yield this.lockService.getActiveLocks('*', 'lock');
|
|
94
|
+
let deletedCount = 0;
|
|
95
|
+
for (const lock of allLocks) {
|
|
96
|
+
if (this.isOwnLock(lock.value)) {
|
|
97
|
+
this.logger.warn(`Found stale lock from this instance: ${lock.key}`);
|
|
98
|
+
yield this.lockService.forceRelease(lock.key);
|
|
99
|
+
deletedCount++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
this.logger.log(`Cleaned up ${deletedCount} locks from this instance`);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
this.logger.error('Failed to cleanup own locks:', error);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Clean up locks from dead instances
|
|
111
|
+
* Only runs after grace period to avoid cleaning locks during rolling updates
|
|
112
|
+
*/
|
|
113
|
+
cleanupDeadInstanceLocks() {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
this.logger.log('Cleaning locks from dead instances...');
|
|
116
|
+
try {
|
|
117
|
+
const allLocks = yield this.lockService.getActiveLocks('*', 'lock');
|
|
118
|
+
let deletedCount = 0;
|
|
119
|
+
for (const lock of allLocks) {
|
|
120
|
+
// Skip own instance's locks
|
|
121
|
+
if (this.isOwnLock(lock.value)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Extract instance ID from lock value
|
|
125
|
+
const instanceId = this.extractInstanceId(lock.value);
|
|
126
|
+
if (!instanceId) {
|
|
127
|
+
// Cannot determine instance, skip (might be old format)
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// Check if instance is alive via heartbeat
|
|
131
|
+
const isAlive = yield this.heartbeatService.isInstanceAlive(instanceId);
|
|
132
|
+
if (!isAlive) {
|
|
133
|
+
this.logger.warn(`Instance ${instanceId} is dead, removing lock: ${lock.key}`);
|
|
134
|
+
yield this.lockService.forceRelease(lock.key);
|
|
135
|
+
deletedCount++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.logger.log(`Cleaned up ${deletedCount} locks from dead instances`);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
this.logger.error('Failed to cleanup dead instance locks:', error);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check if a lock belongs to the current instance
|
|
147
|
+
*
|
|
148
|
+
* @param lockValue - Lock value to check
|
|
149
|
+
* @returns True if lock belongs to current instance
|
|
150
|
+
*/
|
|
151
|
+
isOwnLock(lockValue) {
|
|
152
|
+
if (!lockValue) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const instanceId = this.extractInstanceId(lockValue);
|
|
156
|
+
return instanceId === this.instanceId;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Extract instance ID from lock value
|
|
160
|
+
* Lock value format: instanceId:timestamp:random:pid
|
|
161
|
+
*
|
|
162
|
+
* @param lockValue - Lock value
|
|
163
|
+
* @returns Instance ID or null if cannot be extracted
|
|
164
|
+
*/
|
|
165
|
+
extractInstanceId(lockValue) {
|
|
166
|
+
if (!lockValue) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
// New format: instanceId:timestamp:random:pid
|
|
170
|
+
const parts = lockValue.split(':');
|
|
171
|
+
return parts.length >= 1 ? parts[0] : null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get instance identifier
|
|
175
|
+
*/
|
|
176
|
+
getInstanceId() {
|
|
177
|
+
return (process.env.HOSTNAME ||
|
|
178
|
+
process.env.INSTANCE_ID ||
|
|
179
|
+
`instance-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Manually trigger cleanup of all stale locks
|
|
183
|
+
* Use with caution - this will clean both own and dead instance locks
|
|
184
|
+
*/
|
|
185
|
+
manualCleanup() {
|
|
186
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
this.logger.log('Manual cleanup triggered');
|
|
188
|
+
const ownLocksCount = yield this.cleanupOwnLocksCount();
|
|
189
|
+
const deadLocksCount = yield this.cleanupDeadInstanceLocksCount();
|
|
190
|
+
this.logger.log(`Manual cleanup completed: ${ownLocksCount} own locks, ${deadLocksCount} dead locks`);
|
|
191
|
+
return {
|
|
192
|
+
ownLocks: ownLocksCount,
|
|
193
|
+
deadLocks: deadLocksCount,
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
cleanupOwnLocksCount() {
|
|
198
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
const allLocks = yield this.lockService.getActiveLocks('*', 'lock');
|
|
200
|
+
let deletedCount = 0;
|
|
201
|
+
for (const lock of allLocks) {
|
|
202
|
+
if (this.isOwnLock(lock.value)) {
|
|
203
|
+
yield this.lockService.forceRelease(lock.key);
|
|
204
|
+
deletedCount++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return deletedCount;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
cleanupDeadInstanceLocksCount() {
|
|
211
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
212
|
+
const allLocks = yield this.lockService.getActiveLocks('*', 'lock');
|
|
213
|
+
let deletedCount = 0;
|
|
214
|
+
for (const lock of allLocks) {
|
|
215
|
+
if (this.isOwnLock(lock.value)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const instanceId = this.extractInstanceId(lock.value);
|
|
219
|
+
if (!instanceId) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const isAlive = yield this.heartbeatService.isInstanceAlive(instanceId);
|
|
223
|
+
if (!isAlive) {
|
|
224
|
+
yield this.lockService.forceRelease(lock.key);
|
|
225
|
+
deletedCount++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return deletedCount;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Cleanup own locks on application shutdown
|
|
233
|
+
* Called when receiving SIGTERM/SIGINT (graceful shutdown)
|
|
234
|
+
*/
|
|
235
|
+
onApplicationShutdown(signal) {
|
|
236
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
237
|
+
this.logger.log(`Application shutting down (signal: ${signal}), cleaning own locks...`);
|
|
238
|
+
try {
|
|
239
|
+
const deletedCount = yield this.cleanupOwnLocksCount();
|
|
240
|
+
this.logger.log(`Graceful shutdown cleanup completed: cleaned ${deletedCount} lock(s) from this instance`);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
this.logger.error('Failed to cleanup own locks on shutdown:', error);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
exports.ComprehensiveLockCleanupService = ComprehensiveLockCleanupService;
|
|
249
|
+
exports.ComprehensiveLockCleanupService = ComprehensiveLockCleanupService = ComprehensiveLockCleanupService_1 = __decorate([
|
|
250
|
+
(0, common_1.Injectable)(),
|
|
251
|
+
__metadata("design:paramtypes", [redis_lock_service_1.RedisLockService,
|
|
252
|
+
lock_heartbeat_service_1.LockHeartbeatService])
|
|
253
|
+
], ComprehensiveLockCleanupService);
|
package/redis-lock/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { RedisLockModule, type RedisLockModuleOptions, REDIS_LOCK_SERVICE, } from './redis-lock.module';
|
|
2
2
|
export { RedisLockService, LockStrategy } from './redis-lock.service';
|
|
3
|
+
export { LockHeartbeatService } from './lock-heartbeat.service';
|
|
4
|
+
export { ComprehensiveLockCleanupService } from './comprehensive-lock-cleanup.service';
|
|
3
5
|
export { UseRedisLock, UseRedisLockOrSkip, UseRedisLockSmart, UseRedisLockOrSkipSmart, setLockService, getLockService, } from './redis-lock.decorator';
|
|
4
6
|
export type { LockOptions, LockResult } from './redis-lock.service';
|
package/redis-lock/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getLockService = exports.setLockService = exports.UseRedisLockOrSkipSmart = exports.UseRedisLockSmart = exports.UseRedisLockOrSkip = exports.UseRedisLock = exports.LockStrategy = exports.RedisLockService = exports.REDIS_LOCK_SERVICE = exports.RedisLockModule = void 0;
|
|
3
|
+
exports.getLockService = exports.setLockService = exports.UseRedisLockOrSkipSmart = exports.UseRedisLockSmart = exports.UseRedisLockOrSkip = exports.UseRedisLock = exports.ComprehensiveLockCleanupService = exports.LockHeartbeatService = exports.LockStrategy = exports.RedisLockService = exports.REDIS_LOCK_SERVICE = exports.RedisLockModule = void 0;
|
|
4
4
|
// Module
|
|
5
5
|
var redis_lock_module_1 = require("./redis-lock.module");
|
|
6
6
|
Object.defineProperty(exports, "RedisLockModule", { enumerable: true, get: function () { return redis_lock_module_1.RedisLockModule; } });
|
|
@@ -9,6 +9,10 @@ Object.defineProperty(exports, "REDIS_LOCK_SERVICE", { enumerable: true, get: fu
|
|
|
9
9
|
var redis_lock_service_1 = require("./redis-lock.service");
|
|
10
10
|
Object.defineProperty(exports, "RedisLockService", { enumerable: true, get: function () { return redis_lock_service_1.RedisLockService; } });
|
|
11
11
|
Object.defineProperty(exports, "LockStrategy", { enumerable: true, get: function () { return redis_lock_service_1.LockStrategy; } });
|
|
12
|
+
var lock_heartbeat_service_1 = require("./lock-heartbeat.service");
|
|
13
|
+
Object.defineProperty(exports, "LockHeartbeatService", { enumerable: true, get: function () { return lock_heartbeat_service_1.LockHeartbeatService; } });
|
|
14
|
+
var comprehensive_lock_cleanup_service_1 = require("./comprehensive-lock-cleanup.service");
|
|
15
|
+
Object.defineProperty(exports, "ComprehensiveLockCleanupService", { enumerable: true, get: function () { return comprehensive_lock_cleanup_service_1.ComprehensiveLockCleanupService; } });
|
|
12
16
|
// Decorators
|
|
13
17
|
var redis_lock_decorator_1 = require("./redis-lock.decorator");
|
|
14
18
|
Object.defineProperty(exports, "UseRedisLock", { enumerable: true, get: function () { return redis_lock_decorator_1.UseRedisLock; } });
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import type Redis from 'ioredis';
|
|
3
|
+
/**
|
|
4
|
+
* Lock heartbeat service
|
|
5
|
+
*
|
|
6
|
+
* Provides heartbeat mechanism for distributed lock instances.
|
|
7
|
+
* Each instance sends periodic heartbeats to Redis to indicate it's alive.
|
|
8
|
+
* Dead instances can be detected by checking if their heartbeat has expired.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* constructor(private heartbeatService: LockHeartbeatService) {}
|
|
13
|
+
*
|
|
14
|
+
* async isInstanceAlive(instanceId: string): Promise<boolean> {
|
|
15
|
+
* return this.heartbeatService.isInstanceAlive(instanceId);
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare class LockHeartbeatService implements OnModuleInit, OnModuleDestroy {
|
|
20
|
+
private readonly logger;
|
|
21
|
+
private readonly instanceId;
|
|
22
|
+
private redis;
|
|
23
|
+
private heartbeatTimer;
|
|
24
|
+
/**
|
|
25
|
+
* Heartbeat interval in milliseconds
|
|
26
|
+
* @default 5000 (5 seconds) - reduced for faster failure detection
|
|
27
|
+
*/
|
|
28
|
+
private readonly heartbeatInterval;
|
|
29
|
+
/**
|
|
30
|
+
* Heartbeat TTL in seconds (3x interval for safety)
|
|
31
|
+
* @default 15 (15 seconds) - adjusted to match new interval
|
|
32
|
+
*/
|
|
33
|
+
private readonly heartbeatTtl;
|
|
34
|
+
constructor();
|
|
35
|
+
onModuleInit(): Promise<void>;
|
|
36
|
+
onModuleDestroy(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Set Redis client (required for dependency injection)
|
|
39
|
+
*/
|
|
40
|
+
setRedisClient(redis: Redis): void;
|
|
41
|
+
/**
|
|
42
|
+
* Send heartbeat to Redis
|
|
43
|
+
* Stores instance information with TTL
|
|
44
|
+
*/
|
|
45
|
+
private sendHeartbeat;
|
|
46
|
+
/**
|
|
47
|
+
* Remove heartbeat record from Redis
|
|
48
|
+
*/
|
|
49
|
+
private removeHeartbeat;
|
|
50
|
+
/**
|
|
51
|
+
* Check if an instance is alive by checking its heartbeat
|
|
52
|
+
*
|
|
53
|
+
* @param instanceId - Instance identifier to check
|
|
54
|
+
* @returns True if instance is alive (heartbeat exists), false otherwise
|
|
55
|
+
*/
|
|
56
|
+
isInstanceAlive(instanceId: string): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Get heartbeat information for an instance
|
|
59
|
+
*
|
|
60
|
+
* @param instanceId - Instance identifier
|
|
61
|
+
* @returns Heartbeat data or null if not found
|
|
62
|
+
*/
|
|
63
|
+
getHeartbeatInfo(instanceId: string): Promise<{
|
|
64
|
+
instanceId: string;
|
|
65
|
+
timestamp: number;
|
|
66
|
+
pid: number;
|
|
67
|
+
} | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Get all active instances (with heartbeat)
|
|
70
|
+
*
|
|
71
|
+
* **Note**: Uses SCAN command to avoid blocking Redis in production.
|
|
72
|
+
*
|
|
73
|
+
* @returns Array of instance IDs that are currently alive
|
|
74
|
+
*/
|
|
75
|
+
getActiveInstances(): Promise<string[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Get current instance ID
|
|
78
|
+
*/
|
|
79
|
+
getInstanceId(): string;
|
|
80
|
+
}
|