@nest-omni/core 4.1.3-3 → 4.1.3-31
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 +175 -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
|
@@ -72,18 +72,23 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
72
72
|
this.redis = null;
|
|
73
73
|
this.defaultOptions = {
|
|
74
74
|
ttl: 300000, // 5 minutes
|
|
75
|
-
retryCount: 0
|
|
76
|
-
retryDelay: 100
|
|
75
|
+
retryCount: 3, // Increased from 0 to provide reasonable retry attempts
|
|
76
|
+
retryDelay: 500, // Increased from 100 to reduce retry frequency
|
|
77
77
|
keyPrefix: 'lock',
|
|
78
78
|
throwOnFailure: false,
|
|
79
79
|
strategy: LockStrategy.SKIP,
|
|
80
80
|
waitTimeout: undefined,
|
|
81
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
|
|
82
85
|
};
|
|
83
86
|
// Set global instance when created
|
|
84
87
|
if (!RedisLockService_1.globalInstance) {
|
|
85
88
|
RedisLockService_1.globalInstance = this;
|
|
86
89
|
}
|
|
90
|
+
// Initialize instance ID
|
|
91
|
+
this.instanceId = this.getInstanceId();
|
|
87
92
|
}
|
|
88
93
|
/**
|
|
89
94
|
* Get the global singleton instance
|
|
@@ -167,8 +172,37 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
167
172
|
*/
|
|
168
173
|
acquireLock(key_1) {
|
|
169
174
|
return __awaiter(this, arguments, void 0, function* (key, options = {}) {
|
|
175
|
+
var _a, _b, _c, _d, _e;
|
|
170
176
|
const redis = yield this.getRedis();
|
|
171
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
|
+
}
|
|
172
206
|
// Handle backward compatibility: if throwOnFailure is true, use THROW strategy
|
|
173
207
|
if (opts.throwOnFailure && !options.strategy) {
|
|
174
208
|
opts.strategy = LockStrategy.THROW;
|
|
@@ -227,16 +261,42 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
227
261
|
}
|
|
228
262
|
// Wait before next attempt (except for last attempt)
|
|
229
263
|
if (attempts < maxAttempts) {
|
|
230
|
-
|
|
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);
|
|
231
268
|
}
|
|
232
269
|
}
|
|
233
270
|
catch (error) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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);
|
|
238
299
|
}
|
|
239
|
-
return { acquired: false, error: errorMessage };
|
|
240
300
|
}
|
|
241
301
|
}
|
|
242
302
|
// Max attempts reached
|
|
@@ -439,6 +499,8 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
439
499
|
*
|
|
440
500
|
* WARNING: Use with caution in production! This will forcefully delete locks.
|
|
441
501
|
*
|
|
502
|
+
* **Note**: Uses SCAN command to avoid blocking Redis in production.
|
|
503
|
+
*
|
|
442
504
|
* @param pattern - Lock pattern (e.g., 'MyService:*' or '*:migration:*')
|
|
443
505
|
* @param keyPrefix - Key prefix (default: 'lock')
|
|
444
506
|
* @returns Number of locks deleted
|
|
@@ -457,14 +519,28 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
457
519
|
const redis = yield this.getRedis();
|
|
458
520
|
const searchPattern = `${keyPrefix}:${pattern}`;
|
|
459
521
|
try {
|
|
460
|
-
|
|
461
|
-
|
|
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) {
|
|
462
531
|
this.logger.debug(`No locks found matching pattern: ${searchPattern}`);
|
|
463
532
|
return 0;
|
|
464
533
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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;
|
|
468
544
|
}
|
|
469
545
|
catch (error) {
|
|
470
546
|
this.logger.error(`Error cleaning up locks by pattern ${searchPattern}: ${error.message}`, error.stack);
|
|
@@ -546,6 +622,8 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
546
622
|
* Get all active locks with optional pattern filtering
|
|
547
623
|
* Useful for monitoring and debugging
|
|
548
624
|
*
|
|
625
|
+
* **Note**: Uses SCAN command to avoid blocking Redis in production.
|
|
626
|
+
*
|
|
549
627
|
* @param pattern - Optional pattern to filter locks (e.g., 'MyService:*')
|
|
550
628
|
* @param keyPrefix - Key prefix (default: 'lock')
|
|
551
629
|
* @returns Array of active lock information
|
|
@@ -555,11 +633,18 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
555
633
|
const redis = yield this.getRedis();
|
|
556
634
|
const searchPattern = `${keyPrefix}:${pattern}`;
|
|
557
635
|
try {
|
|
558
|
-
|
|
559
|
-
|
|
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) {
|
|
560
645
|
return [];
|
|
561
646
|
}
|
|
562
|
-
const locks = yield Promise.all(
|
|
647
|
+
const locks = yield Promise.all(allKeys.map((key) => __awaiter(this, void 0, void 0, function* () {
|
|
563
648
|
const [value, ttl] = yield Promise.all([
|
|
564
649
|
redis.get(key),
|
|
565
650
|
redis.pttl(key),
|
|
@@ -596,11 +681,33 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
|
|
|
596
681
|
}
|
|
597
682
|
/**
|
|
598
683
|
* Generate a unique lock value
|
|
684
|
+
* Format: instanceId:timestamp:random:pid
|
|
599
685
|
*
|
|
600
686
|
* @returns Unique lock identifier
|
|
601
687
|
*/
|
|
602
688
|
generateLockValue() {
|
|
603
|
-
|
|
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)}`;
|
|
604
711
|
}
|
|
605
712
|
/**
|
|
606
713
|
* Build the full Redis key for a lock
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import '../common/boilerplate.polyfill';
|
|
1
2
|
import type { NestExpressApplication } from '@nestjs/platform-express';
|
|
2
|
-
export declare function bootstrapSetup(AppModule: any, SetupSwagger: any): Promise<NestExpressApplication<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>>;
|
|
3
|
+
export declare function bootstrapSetup(AppModule: any, SetupSwagger: any): Promise<NestExpressApplication<import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>>>;
|
package/setup/bootstrap.setup.js
CHANGED
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.bootstrapSetup = bootstrapSetup;
|
|
13
|
+
require("../common/boilerplate.polyfill");
|
|
13
14
|
const Sentry = require("@sentry/nestjs");
|
|
14
15
|
const profiling_node_1 = require("@sentry/profiling-node");
|
|
15
16
|
const dotenv = require("dotenv");
|
|
@@ -163,7 +164,7 @@ function bootstrapSetup(AppModule, SetupSwagger) {
|
|
|
163
164
|
}).use, (0, __1.RequestIdMiddleware)(), (0, __1.PowerByMiddleware)(), (0, __1.OmniAuthMiddleware)(), compression());
|
|
164
165
|
// 全局过滤器
|
|
165
166
|
const reflector = app.get(core_1.Reflector);
|
|
166
|
-
app.useGlobalFilters(new setup_1.SentryGlobalFilter(), new __1.HttpExceptionFilter(), new __1.QueryFailedFilter(reflector));
|
|
167
|
+
app.useGlobalFilters(new setup_1.SentryGlobalFilter(), new __1.HttpExceptionFilter(logger), new __1.QueryFailedFilter(reflector));
|
|
167
168
|
// 全局拦截器
|
|
168
169
|
app.useGlobalInterceptors(new __1.LanguageInterceptor(), new __1.TranslationInterceptor(), new nestjs_pino_1.LoggerErrorInterceptor());
|
|
169
170
|
// 全局管道
|
|
@@ -172,7 +173,7 @@ function bootstrapSetup(AppModule, SetupSwagger) {
|
|
|
172
173
|
errorHttpStatusCode: common_1.HttpStatus.UNPROCESSABLE_ENTITY,
|
|
173
174
|
transform: true,
|
|
174
175
|
stopAtFirstError: true,
|
|
175
|
-
validationError: { target:
|
|
176
|
+
validationError: { target: true, value: true },
|
|
176
177
|
}));
|
|
177
178
|
// 可选功能模块 - 仅在 HTTP 或 Hybrid 模式下启用
|
|
178
179
|
if (shouldStartHttp) {
|
package/setup/index.d.ts
CHANGED
package/setup/index.js
CHANGED
|
@@ -18,3 +18,4 @@ __exportStar(require("./bootstrap.setup"), exports);
|
|
|
18
18
|
__exportStar(require("./mode.setup"), exports);
|
|
19
19
|
__exportStar(require("./worker.decorator"), exports);
|
|
20
20
|
__exportStar(require("./schedule.decorator"), exports);
|
|
21
|
+
__exportStar(require("./run-in-mode.decorator"), exports);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mode-Aware Method Decorators
|
|
3
|
+
*
|
|
4
|
+
* Conditional method execution based on application mode:
|
|
5
|
+
* - HTTP: Only HTTP server (no workers/schedulers)
|
|
6
|
+
* - WORKER: Only background workers and schedulers (no HTTP server)
|
|
7
|
+
* - HYBRID: Both HTTP server and workers (default)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Method only executes in HTTP mode (skipped in WORKER and HYBRID)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @RunOnlyInHttp()
|
|
15
|
+
* async handleApiRequest() {
|
|
16
|
+
* // Only runs when APP_MODE=http
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function RunOnlyInHttp(): MethodDecorator;
|
|
21
|
+
/**
|
|
22
|
+
* Method only executes in WORKER mode (skipped in HTTP and HYBRID)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* @RunOnlyInWorker()
|
|
27
|
+
* async processBackgroundJob() {
|
|
28
|
+
* // Only runs when APP_MODE=worker
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function RunOnlyInWorker(): MethodDecorator;
|
|
33
|
+
/**
|
|
34
|
+
* Method executes in HTTP or HYBRID mode (skipped in WORKER-only mode)
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* @RunInHttpOrHybrid()
|
|
39
|
+
* async handleWebRequest() {
|
|
40
|
+
* // Runs in HTTP or HYBRID mode
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function RunInHttpOrHybrid(): MethodDecorator;
|
|
45
|
+
/**
|
|
46
|
+
* Method executes in WORKER or HYBRID mode (skipped in HTTP-only mode)
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* @RunInWorkerOrHybrid()
|
|
51
|
+
* async processScheduledTask() {
|
|
52
|
+
* // Runs in WORKER or HYBRID mode
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function RunInWorkerOrHybrid(): MethodDecorator;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Mode-Aware Method Decorators
|
|
4
|
+
*
|
|
5
|
+
* Conditional method execution based on application mode:
|
|
6
|
+
* - HTTP: Only HTTP server (no workers/schedulers)
|
|
7
|
+
* - WORKER: Only background workers and schedulers (no HTTP server)
|
|
8
|
+
* - HYBRID: Both HTTP server and workers (default)
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.RunOnlyInHttp = RunOnlyInHttp;
|
|
12
|
+
exports.RunOnlyInWorker = RunOnlyInWorker;
|
|
13
|
+
exports.RunInHttpOrHybrid = RunInHttpOrHybrid;
|
|
14
|
+
exports.RunInWorkerOrHybrid = RunInWorkerOrHybrid;
|
|
15
|
+
const common_1 = require("@nestjs/common");
|
|
16
|
+
const mode_setup_1 = require("./mode.setup");
|
|
17
|
+
/**
|
|
18
|
+
* Create mode-restricted decorator
|
|
19
|
+
*/
|
|
20
|
+
function createModeDecorator(allowedModes) {
|
|
21
|
+
return function (target, propertyKey, descriptor) {
|
|
22
|
+
const originalMethod = descriptor.value;
|
|
23
|
+
const className = target.constructor.name;
|
|
24
|
+
const methodName = String(propertyKey);
|
|
25
|
+
const logger = new common_1.Logger(`${className}.${methodName}`);
|
|
26
|
+
descriptor.value = function (...args) {
|
|
27
|
+
const currentMode = (0, mode_setup_1.getApplicationMode)();
|
|
28
|
+
if (!allowedModes.includes(currentMode)) {
|
|
29
|
+
logger.log(`Skipped (current: ${currentMode}, allowed: ${allowedModes.join(', ')})`);
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
return originalMethod.apply(this, args);
|
|
33
|
+
};
|
|
34
|
+
return descriptor;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Method only executes in HTTP mode (skipped in WORKER and HYBRID)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* @RunOnlyInHttp()
|
|
43
|
+
* async handleApiRequest() {
|
|
44
|
+
* // Only runs when APP_MODE=http
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
function RunOnlyInHttp() {
|
|
49
|
+
return createModeDecorator([mode_setup_1.ApplicationMode.HTTP]);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Method only executes in WORKER mode (skipped in HTTP and HYBRID)
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* @RunOnlyInWorker()
|
|
57
|
+
* async processBackgroundJob() {
|
|
58
|
+
* // Only runs when APP_MODE=worker
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
function RunOnlyInWorker() {
|
|
63
|
+
return createModeDecorator([mode_setup_1.ApplicationMode.WORKER]);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Method executes in HTTP or HYBRID mode (skipped in WORKER-only mode)
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* @RunInHttpOrHybrid()
|
|
71
|
+
* async handleWebRequest() {
|
|
72
|
+
* // Runs in HTTP or HYBRID mode
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function RunInHttpOrHybrid() {
|
|
77
|
+
return createModeDecorator([mode_setup_1.ApplicationMode.HTTP, mode_setup_1.ApplicationMode.HYBRID]);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Method executes in WORKER or HYBRID mode (skipped in HTTP-only mode)
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* @RunInWorkerOrHybrid()
|
|
85
|
+
* async processScheduledTask() {
|
|
86
|
+
* // Runs in WORKER or HYBRID mode
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
function RunInWorkerOrHybrid() {
|
|
91
|
+
return createModeDecorator([mode_setup_1.ApplicationMode.WORKER, mode_setup_1.ApplicationMode.HYBRID]);
|
|
92
|
+
}
|
|
@@ -123,6 +123,7 @@ export declare function WorkerTimeout(timeout: number, name?: string): MethodDec
|
|
|
123
123
|
* @param lockKeyOrOptions - Lock key (string) or options object
|
|
124
124
|
* @param lockTtl - Lock TTL in milliseconds (only if lockKeyOrOptions is a string)
|
|
125
125
|
*
|
|
126
|
+
* @param cronOptions
|
|
126
127
|
* @example
|
|
127
128
|
* ```typescript
|
|
128
129
|
* // Using string lock key
|
|
@@ -31,7 +31,7 @@ exports.WorkerCronAdvanced = WorkerCronAdvanced;
|
|
|
31
31
|
const common_1 = require("@nestjs/common");
|
|
32
32
|
const schedule_1 = require("@nestjs/schedule");
|
|
33
33
|
const mode_setup_1 = require("./mode.setup");
|
|
34
|
-
const
|
|
34
|
+
const redis_lock_1 = require("../redis-lock");
|
|
35
35
|
/**
|
|
36
36
|
* Generate a lock key from class name and method name
|
|
37
37
|
*/
|
|
@@ -73,10 +73,14 @@ function executeWithRetry(fn, options) {
|
|
|
73
73
|
function createWorkerDecorator(baseDecorator, decoratorName) {
|
|
74
74
|
return function (target, propertyKey, descriptor) {
|
|
75
75
|
const originalMethod = descriptor.value;
|
|
76
|
+
const className = target.constructor.name;
|
|
77
|
+
const methodName = String(propertyKey);
|
|
78
|
+
const logger = new common_1.Logger(`${className}.${methodName}`);
|
|
76
79
|
descriptor.value = function (...args) {
|
|
77
80
|
return __awaiter(this, void 0, void 0, function* () {
|
|
78
81
|
// Only execute in worker or hybrid mode
|
|
79
82
|
if (!(0, mode_setup_1.shouldProcessQueues)()) {
|
|
83
|
+
logger.log('Skipped (scheduled tasks require WORKER or HYBRID mode)');
|
|
80
84
|
return;
|
|
81
85
|
}
|
|
82
86
|
return originalMethod.apply(this, args);
|
|
@@ -102,12 +106,23 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
|
|
|
102
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
107
|
// Only execute in worker or hybrid mode
|
|
104
108
|
if (!(0, mode_setup_1.shouldProcessQueues)()) {
|
|
109
|
+
logger.log('Skipped (scheduled tasks require WORKER or HYBRID mode)');
|
|
105
110
|
return;
|
|
106
111
|
}
|
|
107
112
|
// Get or create global instance - auto-configures from environment variables
|
|
108
|
-
const lockService =
|
|
109
|
-
const { lockTtl =
|
|
110
|
-
retryCount =
|
|
113
|
+
const lockService = redis_lock_1.RedisLockService.getOrCreateGlobalInstance();
|
|
114
|
+
const { lockTtl = 600000, // 10 minutes default (reduced from 1 hour)
|
|
115
|
+
retryCount = 3, retryDelay = 500, useExponentialBackoff = true, maxRetryDelay = 30000, logExecution = true, lockKeyPrefix = 'schedule', autoExtendLock = 0, onSuccess, onError, skipIfLocked = true, } = options;
|
|
116
|
+
// Configuration validation and adjustment
|
|
117
|
+
const validatedLockTtl = lockTtl >= 3600000
|
|
118
|
+
? (logger.warn(`lockTtl (${lockTtl}ms) is quite long for a scheduled task, consider if this is appropriate for ${className}.${methodName}`), lockTtl)
|
|
119
|
+
: lockTtl;
|
|
120
|
+
const validatedRetryCount = retryCount > 10
|
|
121
|
+
? (logger.warn(`retryCount (${retryCount}) is too high, limiting to 10 for task ${className}.${methodName}`), 10)
|
|
122
|
+
: retryCount;
|
|
123
|
+
const validatedRetryDelay = retryDelay < 100
|
|
124
|
+
? (logger.warn(`retryDelay (${retryDelay}ms) is too low, setting to 100ms for task ${className}.${methodName}`), 100)
|
|
125
|
+
: retryDelay;
|
|
111
126
|
const fullLockKey = `${lockKeyPrefix}:${resolvedLockKey}`;
|
|
112
127
|
const startTime = Date.now();
|
|
113
128
|
// Log task start
|
|
@@ -117,7 +132,7 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
|
|
|
117
132
|
try {
|
|
118
133
|
// Acquire lock
|
|
119
134
|
const lockResult = yield lockService.acquireLock(resolvedLockKey, {
|
|
120
|
-
ttl:
|
|
135
|
+
ttl: validatedLockTtl,
|
|
121
136
|
keyPrefix: lockKeyPrefix,
|
|
122
137
|
autoExtend: autoExtendLock,
|
|
123
138
|
});
|
|
@@ -133,8 +148,8 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
|
|
|
133
148
|
try {
|
|
134
149
|
// Execute with retry logic
|
|
135
150
|
const result = yield executeWithRetry(() => originalMethod.apply(this, args), {
|
|
136
|
-
retryCount,
|
|
137
|
-
retryDelay,
|
|
151
|
+
retryCount: validatedRetryCount,
|
|
152
|
+
retryDelay: validatedRetryDelay,
|
|
138
153
|
useExponentialBackoff,
|
|
139
154
|
maxRetryDelay,
|
|
140
155
|
logger,
|
|
@@ -164,9 +179,8 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
|
|
|
164
179
|
}
|
|
165
180
|
catch (error) {
|
|
166
181
|
const duration = Date.now() - startTime;
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
182
|
+
// Always log errors regardless of logExecution setting
|
|
183
|
+
logger.error(`Task failed after ${duration}ms: ${error.message}`, error.stack);
|
|
170
184
|
// Call error callback with proper this context
|
|
171
185
|
if (onError) {
|
|
172
186
|
yield onError.call(this, error);
|
|
@@ -251,6 +265,7 @@ function WorkerTimeout(timeout, name) {
|
|
|
251
265
|
* @param lockKeyOrOptions - Lock key (string) or options object
|
|
252
266
|
* @param lockTtl - Lock TTL in milliseconds (only if lockKeyOrOptions is a string)
|
|
253
267
|
*
|
|
268
|
+
* @param cronOptions
|
|
254
269
|
* @example
|
|
255
270
|
* ```typescript
|
|
256
271
|
* // Using string lock key
|
|
@@ -309,11 +324,11 @@ function WorkerIntervalWithLock(timeout, lockKeyOrOptions, lockTtl) {
|
|
|
309
324
|
let options;
|
|
310
325
|
if (typeof lockKeyOrOptions === 'string') {
|
|
311
326
|
lockKey = lockKeyOrOptions;
|
|
312
|
-
options = { lockTtl: lockTtl || Math.floor(timeout * 0.8) };
|
|
327
|
+
options = { lockTtl: lockTtl || Math.max(Math.floor(timeout * 0.8), 10000) };
|
|
313
328
|
}
|
|
314
329
|
else {
|
|
315
330
|
lockKey = generateLockKey(target.constructor.name, String(propertyKey));
|
|
316
|
-
options = Object.assign({ lockTtl: Math.floor(timeout * 0.8) }, lockKeyOrOptions);
|
|
331
|
+
options = Object.assign({ lockTtl: Math.max(Math.floor(timeout * 0.8), 10000) }, lockKeyOrOptions);
|
|
317
332
|
}
|
|
318
333
|
return createWorkerDecoratorWithLock((0, schedule_1.Interval)(timeout), 'WorkerIntervalWithLock', lockKey, options)(target, propertyKey, descriptor);
|
|
319
334
|
};
|
|
@@ -406,7 +421,7 @@ function WorkerCronSmart(cronTime, options = {}, cronOptions) {
|
|
|
406
421
|
function WorkerIntervalSmart(timeout, options = {}) {
|
|
407
422
|
return function (target, propertyKey, descriptor) {
|
|
408
423
|
const lockKey = generateLockKey(target.constructor.name, String(propertyKey));
|
|
409
|
-
return createWorkerDecoratorWithLock((0, schedule_1.Interval)(timeout), 'WorkerIntervalSmart', lockKey, Object.assign({ lockTtl: Math.floor(timeout * 0.8), logExecution: true }, options))(target, propertyKey, descriptor);
|
|
424
|
+
return createWorkerDecoratorWithLock((0, schedule_1.Interval)(timeout), 'WorkerIntervalSmart', lockKey, Object.assign({ lockTtl: Math.max(Math.floor(timeout * 0.8), 10000), logExecution: true }, options))(target, propertyKey, descriptor);
|
|
410
425
|
};
|
|
411
426
|
}
|
|
412
427
|
/**
|
|
@@ -20,6 +20,7 @@ exports.WorkerOnQueueCleaned = WorkerOnQueueCleaned;
|
|
|
20
20
|
exports.WorkerOnQueueDrained = WorkerOnQueueDrained;
|
|
21
21
|
exports.WorkerOnQueuePaused = WorkerOnQueuePaused;
|
|
22
22
|
exports.WorkerOnQueueResumed = WorkerOnQueueResumed;
|
|
23
|
+
const common_1 = require("@nestjs/common");
|
|
23
24
|
const bull_1 = require("@nestjs/bull");
|
|
24
25
|
const mode_setup_1 = require("./mode.setup");
|
|
25
26
|
/**
|
|
@@ -67,8 +68,16 @@ function WorkerProcess(name) {
|
|
|
67
68
|
if ((0, mode_setup_1.shouldProcessQueues)()) {
|
|
68
69
|
return (0, bull_1.Process)(name);
|
|
69
70
|
}
|
|
70
|
-
// In HTTP-only mode, return a
|
|
71
|
+
// In HTTP-only mode, return a decorator that logs and skips
|
|
71
72
|
return function (target, propertyKey, descriptor) {
|
|
73
|
+
const originalMethod = descriptor.value;
|
|
74
|
+
const className = target.constructor.name;
|
|
75
|
+
const methodName = String(propertyKey);
|
|
76
|
+
const logger = new common_1.Logger(`${className}.${methodName}`);
|
|
77
|
+
descriptor.value = function (...args) {
|
|
78
|
+
logger.log('Skipped (queue processors require WORKER or HYBRID mode)');
|
|
79
|
+
return undefined;
|
|
80
|
+
};
|
|
72
81
|
return descriptor;
|
|
73
82
|
};
|
|
74
83
|
}
|
package/shared/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './service-registry.module';
|
|
2
2
|
export * from './services';
|
package/shared/index.js
CHANGED
|
@@ -14,5 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./service-registry.module"), exports);
|
|
18
18
|
__exportStar(require("./services"), exports);
|