@fluojs/cron 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -25,6 +25,8 @@ npm install @fluojs/cron croner
25
25
 
26
26
  `croner`는 `@fluojs/cron`이 사용하는 scheduler engine입니다. 애플리케이션과 배포 감사에서 runtime scheduler dependency ownership이 명확히 보이도록 패키지와 함께 설치하세요.
27
27
 
28
+ `@fluojs/redis`는 Redis distributed locking을 활성화할 때만 필요합니다. Non-distributed scheduling 경로는 package import, module registration, bootstrap, status snapshot 생성 중 Redis integration을 로드하지 않습니다.
29
+
28
30
  ## 사용 시점
29
31
 
30
32
  - 정기적인 백그라운드 작업(예: 데이터베이스 정리, 리포트 생성)이 필요할 때 사용합니다.
@@ -39,6 +41,8 @@ npm install @fluojs/cron croner
39
41
  애플리케이션 모듈의 스케줄링 등록은 `CronModule.forRoot(...)`로 구성합니다.
40
42
  Cron 표현식은 다섯 필드(`minute hour day month weekday`) 또는 여섯 필드(`second minute hour day month weekday`)를 사용할 수 있습니다. 내장 `CronExpression` preset은 sub-minute 정밀도가 필요할 때 여섯 필드 표현식을 사용합니다. Cron task는 application bootstrap 이후에만 시작되고, 이미 시작된 registry에 동적으로 등록한 cron task는 등록 시점에 시작되며, fluo는 `timezone`과 no-overlap 보호를 scheduler에 전달해 같은 task instance가 자기 자신과 겹쳐 실행되지 않게 합니다.
41
43
 
44
+ Scheduling decorator는 public instance method에만 적용됩니다. NestJS에서 사용하던 private scheduled method, static helper, legacy decorator metadata 가정 뒤에 숨은 method name을 그대로 옮기지 마세요. 공개 provider/controller method를 노출하고 private 구현 세부사항은 그 method 뒤에 두세요.
45
+
42
46
  ```typescript
43
47
  import { Module } from '@fluojs/core';
44
48
  import { CronModule, Cron, CronExpression, Interval, Timeout } from '@fluojs/cron';
@@ -71,7 +75,7 @@ class AppModule {}
71
75
 
72
76
  ### 분산 락 사용하기
73
77
 
74
- 여러 서버 인스턴스에서 스케줄링된 작업이 동시에 실행되는 것을 방지하려면 분산 모드를 활성화하세요. 이 기능은 `@fluojs/redis`가 필요합니다.
78
+ 여러 서버 인스턴스에서 스케줄링된 작업이 동시에 실행되는 것을 방지하려면 분산 모드를 활성화하세요. 이 기능은 `@fluojs/redis`가 필요하며, Redis peer는 `distributed.enabled`가 `true`일 때만 로드되고 resolve됩니다.
75
79
 
76
80
  ```typescript
77
81
  import { Module } from '@fluojs/core';
@@ -135,15 +139,19 @@ class TaskManager {
135
139
  });
136
140
  }
137
141
 
142
+ speedUpPolling() {
143
+ this.registry.updateIntervalMs('inventory.poll', 5_000);
144
+ }
145
+
138
146
  stopTask() {
139
147
  this.registry.remove('dynamic-job');
140
148
  }
141
149
  }
142
150
  ```
143
151
 
144
- Registry는 `addCron`, `addInterval`, `addTimeout`, `remove`, `enable`, `disable`, `get`, `getAll`, `updateCronExpression`을 제공합니다. Timeout task는 한 번 실행된 뒤 비활성화되지만 registry에는 남아 있어 의도적으로 다시 활성화할 수 있습니다.
152
+ Registry는 `addCron`, `addInterval`, `addTimeout`, `remove`, `enable`, `disable`, `get`, `getAll`, `updateCronExpression`, `updateIntervalMs`를 제공합니다. 첫 번째 `name` 인자는 기본 registry key이며, `options.name`을 전달하면 dynamic task의 실제 registry key, scheduler metadata name, 기본 distributed lock key가 이를 사용해 decorator naming semantics와 일치합니다. `get`과 `getAll`은 live `CronJob` handle이 아니라 read-only `SchedulingTaskDescriptor` 값을 반환합니다. Timeout task는 한 번 실행된 뒤 비활성화되지만 registry에는 남아 있어 의도적으로 다시 활성화할 수 있습니다.
145
153
 
146
- Dynamic cron 등록은 scheduler startup과 원자적으로 처리됩니다. Scheduler가 새 cron job을 거부하면 registry는 half-registered task를 남기지 않습니다. 실행 중인 cron expression update도 rollback-safe합니다. Rescheduling이 실패하면 이전 expression scheduled job이 그대로 유지됩니다. Cron task는 scheduler-level no-overlap protection과 fluo의 in-process running guard를 함께 사용하므로 같은 task instance가 overlapping tick으로 실행되지 않습니다.
154
+ Dynamic cron 등록은 scheduler startup과 원자적으로 처리됩니다. Scheduler가 새 cron job을 거부하면 registry는 half-registered task를 남기지 않습니다. 실행 중인 cron expression 또는 interval cadence update도 rollback-safe합니다. Rescheduling이 실패하면 이전 expression 또는 interval milliseconds와 scheduled handle이 그대로 유지됩니다. Cron task는 scheduler-level no-overlap protection과 fluo의 in-process running guard를 함께 사용하므로 같은 task instance가 overlapping tick으로 실행되지 않습니다.
147
155
 
148
156
  ### 제한된 종료
149
157
 
package/README.md CHANGED
@@ -25,6 +25,8 @@ npm install @fluojs/cron croner
25
25
 
26
26
  `croner` is the scheduler engine used by `@fluojs/cron`. Install it alongside the package so lockfiles make the runtime scheduler dependency explicit for applications and deployment audits.
27
27
 
28
+ `@fluojs/redis` is needed only when Redis distributed locking is enabled. Non-distributed scheduling paths do not load the Redis integration during package import, module registration, bootstrap, or status snapshot creation.
29
+
28
30
  ## When to Use
29
31
 
30
32
  - When you need to run periodic background tasks (e.g., database cleanup, report generation).
@@ -39,6 +41,8 @@ Register the `CronModule` and use decorators to schedule your methods.
39
41
  Use `CronModule.forRoot(...)` to register scheduling for an application module.
40
42
  Cron expressions may use either five fields (`minute hour day month weekday`) or six fields (`second minute hour day month weekday`). The built-in `CronExpression` presets use six-field expressions when sub-minute precision is needed. Cron tasks start only after application bootstrap, dynamically registered cron tasks start when added to a started registry, and fluo forwards `timezone` plus no-overlap protection to the scheduler so one task instance does not overlap itself.
41
43
 
44
+ Scheduling decorators apply to public instance methods only. Do not migrate NestJS private scheduled methods, static helpers, or method names that are hidden behind legacy decorator metadata assumptions as-is; expose a public provider/controller method and keep any private implementation details behind that method.
45
+
42
46
  ```typescript
43
47
  import { Module } from '@fluojs/core';
44
48
  import { CronModule, Cron, CronExpression, Interval, Timeout } from '@fluojs/cron';
@@ -71,7 +75,7 @@ class AppModule {}
71
75
 
72
76
  ### Distributed Locking
73
77
 
74
- To prevent scheduled tasks from running concurrently across multiple server instances, enable distributed mode. This requires `@fluojs/redis`.
78
+ To prevent scheduled tasks from running concurrently across multiple server instances, enable distributed mode. This requires `@fluojs/redis`; the Redis peer is loaded and resolved only when `distributed.enabled` is `true`.
75
79
 
76
80
  ```typescript
77
81
  import { Module } from '@fluojs/core';
@@ -135,15 +139,19 @@ class TaskManager {
135
139
  });
136
140
  }
137
141
 
142
+ speedUpPolling() {
143
+ this.registry.updateIntervalMs('inventory.poll', 5_000);
144
+ }
145
+
138
146
  stopTask() {
139
147
  this.registry.remove('dynamic-job');
140
148
  }
141
149
  }
142
150
  ```
143
151
 
144
- The registry exposes `addCron`, `addInterval`, `addTimeout`, `remove`, `enable`, `disable`, `get`, `getAll`, and `updateCronExpression`. Timeout tasks run once, then disable themselves while remaining in the registry so they can be re-enabled deliberately.
152
+ The registry exposes `addCron`, `addInterval`, `addTimeout`, `remove`, `enable`, `disable`, `get`, `getAll`, `updateCronExpression`, and `updateIntervalMs`. The first `name` argument is the default registry key; passing `options.name` overrides the actual registry key, scheduler metadata name, and default distributed lock key for dynamic tasks so dynamic registration matches decorator naming semantics. `get` and `getAll` return read-only `SchedulingTaskDescriptor` values, not live `CronJob` handles. Timeout tasks run once, then disable themselves while remaining in the registry so they can be re-enabled deliberately.
145
153
 
146
- Dynamic cron registration is atomic with scheduler startup: if the scheduler rejects a new cron job, the registry does not retain a half-registered task. Updating a running cron expression is also rollback-safe. If rescheduling fails, the previous expression and scheduled job remain active. Cron tasks use both scheduler-level no-overlap protection and fluo's in-process running guard, so the same task instance will not run overlapping ticks.
154
+ Dynamic cron registration is atomic with scheduler startup: if the scheduler rejects a new cron job, the registry does not retain a half-registered task. Updating a running cron expression or interval cadence is also rollback-safe. If rescheduling fails, the previous expression or interval milliseconds and scheduled handle remain active. Cron tasks use both scheduler-level no-overlap protection and fluo's in-process running guard, so the same task instance will not run overlapping ticks.
147
155
 
148
156
  ### Bounded Shutdown
149
157
 
@@ -17,19 +17,21 @@ export declare class CronDistributedLockManager {
17
17
  private readonly runtimeContainer;
18
18
  private readonly logger;
19
19
  private readonly ownedLockKeys;
20
+ private lockIoError;
20
21
  private redisClient;
21
22
  private lockOwnershipLosses;
22
23
  private lockRenewalFailures;
23
24
  constructor(options: NormalizedCronModuleOptions, runtimeContainer: Container, logger: ApplicationLogger);
24
25
  get resolvedClient(): RedisLockClient | undefined;
25
26
  get ownedLocks(): number;
27
+ get lockIoAvailable(): boolean;
26
28
  get ownershipLosses(): number;
27
29
  get renewalFailures(): number;
28
30
  resolveClient(): Promise<void>;
29
31
  reset(): void;
30
32
  tryAcquireLock(descriptor: CronTaskDescriptor): Promise<boolean>;
31
33
  startLockRenewalMonitor(descriptor: CronTaskDescriptor): LockRenewalMonitor;
32
- releaseLock(descriptor: CronTaskDescriptor): Promise<void>;
34
+ releaseLock(descriptor: CronTaskDescriptor): Promise<boolean>;
33
35
  releaseOwnedLocks(excludedLockKeys?: ReadonlySet<string>): Promise<void>;
34
36
  private createLockRenewalState;
35
37
  private queueDueLockRenewalAttempts;
@@ -37,5 +39,8 @@ export declare class CronDistributedLockManager {
37
39
  private toLockPostRunError;
38
40
  private renewLock;
39
41
  private releaseLockKey;
42
+ private verifyLockIoAvailability;
43
+ private markLockIoAvailable;
44
+ private markLockIoUnavailable;
40
45
  }
41
46
  //# sourceMappingURL=distributed-lock-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"distributed-lock-manager.d.ts","sourceRoot":"","sources":["../src/distributed-lock-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAElF,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC7G;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,eAAe,IAAI,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAC9C,IAAI,IAAI,IAAI,CAAC;CACd;AAiBD,yFAAyF;AACzF,qBAAa,0BAA0B;IAOnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,mBAAmB,CAAK;gBAGb,OAAO,EAAE,2BAA2B,EACpC,gBAAgB,EAAE,SAAS,EAC3B,MAAM,EAAE,iBAAiB;IAG5C,IAAI,cAAc,IAAI,eAAe,GAAG,SAAS,CAEhD;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAEK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBpC,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IA+BtE,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,kBAAkB;IA8BrE,WAAW,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D,iBAAiB,CAAC,gBAAgB,GAAE,WAAW,CAAC,MAAM,CAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzF,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,2BAA2B;YAcrB,qBAAqB;IAqBnC,OAAO,CAAC,kBAAkB;YAYZ,SAAS;YAwCT,cAAc;CAgC7B"}
1
+ {"version":3,"file":"distributed-lock-manager.d.ts","sourceRoot":"","sources":["../src/distributed-lock-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAElF,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC7G;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,eAAe,IAAI,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAC9C,IAAI,IAAI,IAAI,CAAC;CACd;AAoDD,yFAAyF;AACzF,qBAAa,0BAA0B;IAQnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM;IATzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,mBAAmB,CAAK;gBAGb,OAAO,EAAE,2BAA2B,EACpC,gBAAgB,EAAE,SAAS,EAC3B,MAAM,EAAE,iBAAiB;IAG5C,IAAI,cAAc,IAAI,eAAe,GAAG,SAAS,CAEhD;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,eAAe,IAAI,OAAO,CAM7B;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAEK,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBpC,KAAK,IAAI,IAAI;IAKP,cAAc,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAkCtE,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,kBAAkB;IA8BrE,WAAW,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7D,iBAAiB,CAAC,gBAAgB,GAAE,WAAW,CAAC,MAAM,CAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzF,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,2BAA2B;YAcrB,qBAAqB;IAqBnC,OAAO,CAAC,kBAAkB;YAYZ,SAAS;YA2CT,cAAc;YAsCd,wBAAwB;IAmBtC,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,qBAAqB;CAG9B"}
@@ -1,15 +1,36 @@
1
- import { getRedisClientToken } from '@fluojs/redis';
2
-
3
1
  /** Minimal Redis command surface required for distributed cron locks. */
4
2
 
5
3
  /** Tracks renewal state for one acquired distributed cron lock. */
6
4
 
7
5
  const RELEASE_LOCK_SCRIPT = 'if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end';
8
6
  const RENEW_LOCK_SCRIPT = 'if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("PEXPIRE", KEYS[1], ARGV[2]) else return 0 end';
7
+ const REDIS_PEER_MODULE_SPECIFIER = '@fluojs/redis';
8
+ const loadRedisPeerModule = async () => import(REDIS_PEER_MODULE_SPECIFIER);
9
+ function isMissingRedisPeer(error) {
10
+ if (!(error instanceof Error)) {
11
+ return false;
12
+ }
13
+ const code = 'code' in error ? error.code : undefined;
14
+ return code === 'ERR_MODULE_NOT_FOUND' && error.message.includes(REDIS_PEER_MODULE_SPECIFIER);
15
+ }
16
+ function createRedisBootstrapError() {
17
+ return new Error(['Cron distributed mode requires @fluojs/redis to be installed and registered.', 'Install and import @fluojs/redis, or disable distributed locking with distributed.enabled: false.'].join(' '));
18
+ }
19
+ async function resolveRedisPeerModule() {
20
+ try {
21
+ return await loadRedisPeerModule();
22
+ } catch (error) {
23
+ if (isMissingRedisPeer(error)) {
24
+ throw createRedisBootstrapError();
25
+ }
26
+ throw error;
27
+ }
28
+ }
9
29
 
10
30
  /** Coordinates Redis lock acquisition, renewal, and release for scheduled cron tasks. */
11
31
  export class CronDistributedLockManager {
12
32
  ownedLockKeys = new Set();
33
+ lockIoError;
13
34
  redisClient;
14
35
  lockOwnershipLosses = 0;
15
36
  lockRenewalFailures = 0;
@@ -24,6 +45,12 @@ export class CronDistributedLockManager {
24
45
  get ownedLocks() {
25
46
  return this.ownedLockKeys.size;
26
47
  }
48
+ get lockIoAvailable() {
49
+ if (!this.options.distributed.enabled) {
50
+ return true;
51
+ }
52
+ return this.redisClient !== undefined && this.lockIoError === undefined;
53
+ }
27
54
  get ownershipLosses() {
28
55
  return this.lockOwnershipLosses;
29
56
  }
@@ -34,6 +61,9 @@ export class CronDistributedLockManager {
34
61
  if (!this.options.distributed.enabled) {
35
62
  return;
36
63
  }
64
+ const {
65
+ getRedisClientToken
66
+ } = await resolveRedisPeerModule();
37
67
  const redisToken = getRedisClientToken(this.options.distributed.clientName);
38
68
  if (!this.runtimeContainer.has(redisToken)) {
39
69
  throw new Error('Cron distributed mode requires the configured Redis client to be registered.');
@@ -43,8 +73,10 @@ export class CronDistributedLockManager {
43
73
  throw new Error('Cron distributed mode requires the configured Redis client to implement set/eval lock operations.');
44
74
  }
45
75
  this.redisClient = redisClient;
76
+ await this.verifyLockIoAvailability();
46
77
  }
47
78
  reset() {
79
+ this.lockIoError = undefined;
48
80
  this.redisClient = undefined;
49
81
  }
50
82
  async tryAcquireLock(descriptor) {
@@ -54,11 +86,13 @@ export class CronDistributedLockManager {
54
86
  }
55
87
  try {
56
88
  const result = await redis.set(descriptor.lockKey, this.options.distributed.ownerId, 'PX', descriptor.lockTtlMs, 'NX');
89
+ this.markLockIoAvailable();
57
90
  if (result === 'OK') {
58
91
  this.ownedLockKeys.add(descriptor.lockKey);
59
92
  }
60
93
  return result === 'OK';
61
94
  } catch (error) {
95
+ this.markLockIoUnavailable(error);
62
96
  this.logger.error(`Failed to acquire distributed cron lock for ${descriptor.taskName}.`, error, 'CronLifecycleService');
63
97
  return false;
64
98
  }
@@ -90,7 +124,7 @@ export class CronDistributedLockManager {
90
124
  };
91
125
  }
92
126
  async releaseLock(descriptor) {
93
- await this.releaseLockKey(descriptor.lockKey, descriptor.taskName);
127
+ return await this.releaseLockKey(descriptor.lockKey, descriptor.taskName);
94
128
  }
95
129
  async releaseOwnedLocks(excludedLockKeys = new Set()) {
96
130
  if (!this.redisClient || this.ownedLockKeys.size === 0) {
@@ -153,12 +187,15 @@ export class CronDistributedLockManager {
153
187
  try {
154
188
  const result = await redis.eval(RENEW_LOCK_SCRIPT, 1, descriptor.lockKey, this.options.distributed.ownerId, String(descriptor.lockTtlMs));
155
189
  if (typeof result === 'number' && result <= 0) {
190
+ this.markLockIoAvailable();
156
191
  this.logger.warn(`Distributed cron lock ownership was lost for ${descriptor.taskName}.`, 'CronLifecycleService');
157
192
  return 'ownership-lost';
158
193
  }
194
+ this.markLockIoAvailable();
159
195
  this.logger.log(`Renewed distributed cron lock for ${descriptor.taskName}.`, 'CronLifecycleService');
160
196
  return 'renewed';
161
197
  } catch (error) {
198
+ this.markLockIoUnavailable(error);
162
199
  this.logger.error(`Failed to renew distributed cron lock for ${descriptor.taskName}.`, error, 'CronLifecycleService');
163
200
  return 'renewal-failed';
164
201
  }
@@ -166,21 +203,47 @@ export class CronDistributedLockManager {
166
203
  async releaseLockKey(lockKey, taskName) {
167
204
  const redis = this.redisClient;
168
205
  if (!redis) {
169
- return;
206
+ return true;
170
207
  }
171
208
  try {
172
209
  const result = await redis.eval(RELEASE_LOCK_SCRIPT, 1, lockKey, this.options.distributed.ownerId);
173
210
  if (typeof result === 'number' && result <= 0) {
211
+ this.markLockIoAvailable();
174
212
  this.logger.warn(`Distributed cron lock for ${taskName} was already released or owned by another node.`, 'CronLifecycleService');
175
213
  this.ownedLockKeys.delete(lockKey);
176
- return;
214
+ return true;
177
215
  }
216
+ this.markLockIoAvailable();
178
217
  this.logger.log(`Released distributed cron lock for ${taskName}.`, 'CronLifecycleService');
179
218
  this.ownedLockKeys.delete(lockKey);
219
+ return true;
180
220
  } catch (error) {
221
+ this.markLockIoUnavailable(error);
181
222
  this.logger.error(`Failed to release distributed cron lock for ${taskName}.`, error, 'CronLifecycleService');
223
+ return false;
182
224
  }
183
225
  }
226
+ async verifyLockIoAvailability() {
227
+ const redis = this.redisClient;
228
+ if (!redis) {
229
+ return;
230
+ }
231
+ const probeKey = `${this.options.distributed.keyPrefix}:__probe:${this.options.distributed.ownerId}`;
232
+ try {
233
+ await redis.set(probeKey, this.options.distributed.ownerId, 'PX', 1_000, 'NX');
234
+ await redis.eval(RELEASE_LOCK_SCRIPT, 1, probeKey, this.options.distributed.ownerId);
235
+ this.markLockIoAvailable();
236
+ } catch (error) {
237
+ this.markLockIoUnavailable(error);
238
+ throw new Error('Cron distributed mode requires Redis lock I/O to be available.');
239
+ }
240
+ }
241
+ markLockIoAvailable() {
242
+ this.lockIoError = undefined;
243
+ }
244
+ markLockIoUnavailable(error) {
245
+ this.lockIoError = error instanceof Error ? error : new Error('Redis lock I/O failed.');
246
+ }
184
247
  }
185
248
  function hasRedisLockClient(value) {
186
249
  if (typeof value !== 'object' || value === null) {
package/dist/service.d.ts CHANGED
@@ -90,12 +90,20 @@ export declare class CronLifecycleService implements SchedulingRegistry, OnAppli
90
90
  * @param expression New cron expression to validate and schedule.
91
91
  */
92
92
  updateCronExpression(name: string, expression: string): void;
93
+ /**
94
+ * Replaces the millisecond cadence of one existing interval task.
95
+ *
96
+ * @param name Name of the interval task to update.
97
+ * @param ms New positive interval in milliseconds.
98
+ */
99
+ updateIntervalMs(name: string, ms: number): void;
93
100
  onApplicationBootstrap(): Promise<void>;
94
101
  onApplicationShutdown(): Promise<void>;
95
102
  onModuleDestroy(): Promise<void>;
96
103
  createPlatformStatusSnapshot(): import("./status.js").CronPlatformStatusSnapshot;
97
104
  private toSchedulingTaskDescriptor;
98
105
  private shutdown;
106
+ private retryReleasedDistributedLocksAfterShutdown;
99
107
  private startLifecycle;
100
108
  private validateDistributedLockConfiguration;
101
109
  private handleStartupFailure;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
package/dist/service.js CHANGED
@@ -5,9 +5,8 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
5
5
  function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
6
  function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
7
  import { Inject } from '@fluojs/core';
8
- import { getRedisComponentId } from '@fluojs/redis';
9
- import { Cron as CronValidator } from 'croner';
10
8
  import { APPLICATION_LOGGER, COMPILED_MODULES, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
9
+ import { Cron as CronValidator } from 'croner';
11
10
  import { CronDistributedLockManager } from './distributed-lock-manager.js';
12
11
  import { createCronPlatformStatusSnapshot } from './status.js';
13
12
  import { createLockKey, discoverCronTaskDescriptors } from './task-discovery.js';
@@ -23,6 +22,14 @@ function assertValidTaskName(name) {
23
22
  throw new Error('Scheduling task name must be a non-empty string.');
24
23
  }
25
24
  }
25
+ function resolveDynamicTaskName(name, optionName) {
26
+ assertValidTaskName(name);
27
+ if (optionName !== undefined) {
28
+ assertValidTaskName(optionName);
29
+ return optionName;
30
+ }
31
+ return name;
32
+ }
26
33
  function assertValidMs(ms, context) {
27
34
  if (!Number.isFinite(ms) || !Number.isInteger(ms) || ms <= 0) {
28
35
  throw new Error(`${context}: ms must be a positive integer.`);
@@ -37,6 +44,16 @@ function assertValidCronExpression(expression) {
37
44
  throw new Error(`@Cron(): invalid cron expression "${expression}".`);
38
45
  }
39
46
  }
47
+ function createRedisDependencyId(name) {
48
+ if (name === undefined) {
49
+ return 'redis.default';
50
+ }
51
+ const normalizedName = name.trim();
52
+ if (normalizedName.length === 0) {
53
+ throw new Error('Redis client name must be a non-empty string.');
54
+ }
55
+ return `redis.${normalizedName}`;
56
+ }
40
57
 
41
58
  /**
42
59
  * Lifecycle-managed scheduler runtime for decorator-discovered and dynamic tasks.
@@ -76,8 +93,8 @@ class CronLifecycleService {
76
93
  * @param options Optional hooks, distributed lock overrides, and timezone.
77
94
  */
78
95
  addCron(name, expression, callback, options = {}) {
79
- assertValidTaskName(name);
80
96
  assertValidCronExpression(expression);
97
+ const taskName = resolveDynamicTaskName(name, options.name);
81
98
  this.registerTask({
82
99
  afterRun: options.afterRun,
83
100
  beforeRun: options.beforeRun,
@@ -85,11 +102,11 @@ class CronLifecycleService {
85
102
  distributed: options.distributed ?? true,
86
103
  expression,
87
104
  kind: 'cron',
88
- lockKey: createLockKey(this.options.distributed.keyPrefix, options.key ?? name),
105
+ lockKey: createLockKey(this.options.distributed.keyPrefix, options.key ?? taskName),
89
106
  lockTtlMs: options.lockTtlMs ?? this.options.distributed.lockTtlMs,
90
107
  onError: options.onError,
91
108
  onSuccess: options.onSuccess,
92
- taskName: name,
109
+ taskName,
93
110
  timezone: options.timezone
94
111
  }, 'dynamic');
95
112
  }
@@ -103,20 +120,20 @@ class CronLifecycleService {
103
120
  * @param options Optional hooks and distributed lock overrides.
104
121
  */
105
122
  addInterval(name, ms, callback, options = {}) {
106
- assertValidTaskName(name);
107
123
  assertValidMs(ms, 'scheduling registry');
124
+ const taskName = resolveDynamicTaskName(name, options.name);
108
125
  this.registerTask({
109
126
  afterRun: options.afterRun,
110
127
  beforeRun: options.beforeRun,
111
128
  callback,
112
129
  distributed: options.distributed ?? true,
113
130
  kind: 'interval',
114
- lockKey: createLockKey(this.options.distributed.keyPrefix, options.key ?? name),
131
+ lockKey: createLockKey(this.options.distributed.keyPrefix, options.key ?? taskName),
115
132
  lockTtlMs: options.lockTtlMs ?? this.options.distributed.lockTtlMs,
116
133
  ms,
117
134
  onError: options.onError,
118
135
  onSuccess: options.onSuccess,
119
- taskName: name
136
+ taskName
120
137
  }, 'dynamic');
121
138
  }
122
139
 
@@ -129,20 +146,20 @@ class CronLifecycleService {
129
146
  * @param options Optional hooks and distributed lock overrides.
130
147
  */
131
148
  addTimeout(name, ms, callback, options = {}) {
132
- assertValidTaskName(name);
133
149
  assertValidMs(ms, 'scheduling registry');
150
+ const taskName = resolveDynamicTaskName(name, options.name);
134
151
  this.registerTask({
135
152
  afterRun: options.afterRun,
136
153
  beforeRun: options.beforeRun,
137
154
  callback,
138
155
  distributed: options.distributed ?? true,
139
156
  kind: 'timeout',
140
- lockKey: createLockKey(this.options.distributed.keyPrefix, options.key ?? name),
157
+ lockKey: createLockKey(this.options.distributed.keyPrefix, options.key ?? taskName),
141
158
  lockTtlMs: options.lockTtlMs ?? this.options.distributed.lockTtlMs,
142
159
  ms,
143
160
  onError: options.onError,
144
161
  onSuccess: options.onSuccess,
145
- taskName: name
162
+ taskName
146
163
  }, 'dynamic');
147
164
  }
148
165
 
@@ -263,6 +280,41 @@ class CronLifecycleService {
263
280
  throw error;
264
281
  }
265
282
  }
283
+
284
+ /**
285
+ * Replaces the millisecond cadence of one existing interval task.
286
+ *
287
+ * @param name Name of the interval task to update.
288
+ * @param ms New positive interval in milliseconds.
289
+ */
290
+ updateIntervalMs(name, ms) {
291
+ assertValidMs(ms, 'scheduling registry');
292
+ const task = this.tasks.get(name);
293
+ if (!task) {
294
+ throw new Error(`Scheduling task "${name}" does not exist.`);
295
+ }
296
+ if (task.descriptor.kind !== 'interval') {
297
+ throw new Error(`updateIntervalMs() supports only interval tasks. Received ${task.descriptor.kind} task "${name}".`);
298
+ }
299
+ if (!task.enabled || !this.started) {
300
+ task.descriptor.ms = ms;
301
+ return;
302
+ }
303
+ const previousMs = task.descriptor.ms;
304
+ const previousHandle = task.scheduledHandle;
305
+ task.descriptor.ms = ms;
306
+ try {
307
+ const nextHandle = this.createScheduledHandle(task);
308
+ task.scheduledHandle = nextHandle;
309
+ if (previousHandle) {
310
+ this.stopScheduledHandle(previousHandle);
311
+ }
312
+ } catch (error) {
313
+ task.descriptor.ms = previousMs;
314
+ task.scheduledHandle = previousHandle;
315
+ throw error;
316
+ }
317
+ }
266
318
  async onApplicationBootstrap() {
267
319
  if (this.started) {
268
320
  return;
@@ -296,7 +348,7 @@ class CronLifecycleService {
296
348
  }
297
349
  return createCronPlatformStatusSnapshot({
298
350
  activeTicks: this.activeTasks.size,
299
- dependencyId: this.options.distributed.enabled ? getRedisComponentId(this.options.distributed.clientName) : undefined,
351
+ dependencyId: this.options.distributed.enabled ? createRedisDependencyId(this.options.distributed.clientName) : undefined,
300
352
  distributedEnabled: this.options.distributed.enabled,
301
353
  enabledTasks,
302
354
  lifecycleState: this.lifecycleState,
@@ -304,6 +356,7 @@ class CronLifecycleService {
304
356
  lockRenewalFailures: this.distributedLocks.renewalFailures,
305
357
  ownedLocks: this.distributedLocks.ownedLocks,
306
358
  redisDependencyResolved: this.distributedLocks.resolvedClient !== undefined,
359
+ redisLockIoAvailable: this.distributedLocks.lockIoAvailable,
307
360
  runningTasks,
308
361
  totalTasks: this.tasks.size
309
362
  });
@@ -328,11 +381,18 @@ class CronLifecycleService {
328
381
  async shutdown() {
329
382
  if (this.shutdownPromise) {
330
383
  await this.shutdownPromise;
384
+ await this.retryReleasedDistributedLocksAfterShutdown();
331
385
  return;
332
386
  }
333
387
  this.shutdownPromise = this.runShutdownLifecycle();
334
388
  await this.shutdownPromise;
335
389
  }
390
+ async retryReleasedDistributedLocksAfterShutdown() {
391
+ if (this.lifecycleState !== 'stopped' || this.activeTasks.size > 0) {
392
+ return;
393
+ }
394
+ await this.distributedLocks.releaseOwnedLocks();
395
+ }
336
396
  async startLifecycle() {
337
397
  await this.distributedLocks.resolveClient();
338
398
  this.validateDistributedLockConfiguration();
@@ -509,8 +569,11 @@ class CronLifecycleService {
509
569
  });
510
570
  } finally {
511
571
  lockRenewalMonitor.stop();
512
- await this.distributedLocks.releaseLock(descriptor);
513
572
  this.runningDistributedLockKeys.delete(descriptor.lockKey);
573
+ const released = await this.distributedLocks.releaseLock(descriptor);
574
+ if (!released && this.lifecycleState === 'stopped') {
575
+ await this.distributedLocks.releaseOwnedLocks();
576
+ }
514
577
  }
515
578
  }
516
579
  async waitForActiveTasks() {
package/dist/status.d.ts CHANGED
@@ -12,6 +12,7 @@ export interface CronStatusAdapterInput {
12
12
  lockRenewalFailures: number;
13
13
  ownedLocks: number;
14
14
  redisDependencyResolved: boolean;
15
+ redisLockIoAvailable?: boolean;
15
16
  runningTasks: number;
16
17
  totalTasks: number;
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEvG,qEAAqE;AACrE,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtG,mFAAmF;AACnF,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,kBAAkB,CAAC;IACnC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB,EAAE,OAAO,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qFAAqF;AACrF,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAoFD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,sBAAsB,GAAG,0BAA0B,CAsB1G"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEvG,qEAAqE;AACrE,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtG,mFAAmF;AACnF,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,kBAAkB,CAAC;IACnC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB,EAAE,OAAO,CAAC;IACjC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qFAAqF;AACrF,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAuGD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,sBAAsB,GAAG,0BAA0B,CAyB1G"}
package/dist/status.js CHANGED
@@ -5,8 +5,9 @@
5
5
  /** Cron-specific platform snapshot returned to health and readiness integrations. */
6
6
 
7
7
  function createReadiness(input) {
8
+ const redisLockIoAvailable = resolveRedisLockIoAvailable(input);
8
9
  if (input.lifecycleState === 'ready') {
9
- if (input.distributedEnabled && !input.redisDependencyResolved) {
10
+ if (input.distributedEnabled && (!input.redisDependencyResolved || !redisLockIoAvailable)) {
10
11
  return {
11
12
  critical: true,
12
13
  reason: 'Distributed cron mode requires a ready Redis lock client.',
@@ -53,6 +54,7 @@ function createReadiness(input) {
53
54
  };
54
55
  }
55
56
  function createHealth(input) {
57
+ const redisLockIoAvailable = resolveRedisLockIoAvailable(input);
56
58
  if (input.lifecycleState === 'failed' || input.lifecycleState === 'stopped') {
57
59
  return {
58
60
  reason: 'Cron scheduler is unavailable.',
@@ -65,6 +67,12 @@ function createHealth(input) {
65
67
  status: 'degraded'
66
68
  };
67
69
  }
70
+ if (input.distributedEnabled && (!input.redisDependencyResolved || !redisLockIoAvailable)) {
71
+ return {
72
+ reason: 'Distributed cron Redis lock I/O is unavailable.',
73
+ status: 'unhealthy'
74
+ };
75
+ }
68
76
  if (input.lockRenewalFailures > 0 || input.lockOwnershipLosses > 0) {
69
77
  return {
70
78
  reason: 'Distributed cron lock renewal reported recoverable failures.',
@@ -75,6 +83,12 @@ function createHealth(input) {
75
83
  status: 'healthy'
76
84
  };
77
85
  }
86
+ function resolveRedisLockIoAvailable(input) {
87
+ if (!input.distributedEnabled) {
88
+ return true;
89
+ }
90
+ return input.redisLockIoAvailable ?? input.redisDependencyResolved;
91
+ }
78
92
 
79
93
  /**
80
94
  * Creates the cron platform snapshot consumed by status reporters.
@@ -83,6 +97,7 @@ function createHealth(input) {
83
97
  * @returns Readiness, health, ownership, and cron detail fields.
84
98
  */
85
99
  export function createCronPlatformStatusSnapshot(input) {
100
+ const redisLockIoAvailable = resolveRedisLockIoAvailable(input);
86
101
  return {
87
102
  details: {
88
103
  activeTicks: input.activeTicks,
@@ -94,6 +109,7 @@ export function createCronPlatformStatusSnapshot(input) {
94
109
  lockRenewalFailures: input.lockRenewalFailures,
95
110
  ownedLocks: input.ownedLocks,
96
111
  redisDependencyResolved: input.redisDependencyResolved,
112
+ redisLockIoAvailable,
97
113
  runningTasks: input.runningTasks,
98
114
  totalTasks: input.totalTasks
99
115
  },
package/dist/types.d.ts CHANGED
@@ -204,5 +204,12 @@ export interface SchedulingRegistry {
204
204
  * @param expression New cron expression validated before rescheduling.
205
205
  */
206
206
  updateCronExpression(name: string, expression: string): void;
207
+ /**
208
+ * Replaces the millisecond cadence for an existing interval task.
209
+ *
210
+ * @param name Task name to update.
211
+ * @param ms New positive interval in milliseconds.
212
+ */
213
+ updateIntervalMs(name: string, ms: number): void;
207
214
  }
208
215
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "timeout",
10
10
  "distributed-lock"
11
11
  ],
12
- "version": "1.0.2",
12
+ "version": "1.1.0",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -37,13 +37,21 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "croner": "^8.1.2",
40
- "@fluojs/core": "^1.0.2",
41
- "@fluojs/di": "^1.0.2",
42
- "@fluojs/redis": "^1.0.0",
43
- "@fluojs/runtime": "^1.1.0"
40
+ "@fluojs/core": "^1.0.3",
41
+ "@fluojs/di": "^1.1.0",
42
+ "@fluojs/runtime": "^1.1.8"
43
+ },
44
+ "peerDependencies": {
45
+ "@fluojs/redis": "^1.0.2"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@fluojs/redis": {
49
+ "optional": true
50
+ }
44
51
  },
45
52
  "devDependencies": {
46
- "vitest": "^3.2.4"
53
+ "vitest": "^3.2.4",
54
+ "@fluojs/redis": "^1.0.2"
47
55
  },
48
56
  "scripts": {
49
57
  "prebuild": "node ../../tooling/scripts/clean-dist.mjs",