@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 +11 -3
- package/README.md +11 -3
- package/dist/distributed-lock-manager.d.ts +6 -1
- package/dist/distributed-lock-manager.d.ts.map +1 -1
- package/dist/distributed-lock-manager.js +68 -5
- package/dist/service.d.ts +8 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +76 -13
- package/dist/status.d.ts +1 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +17 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +14 -6
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
|
|
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
|
|
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 `
|
|
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
|
|
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<
|
|
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":"
|
|
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;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AASzB,OAAO,KAAK,EAEV,eAAe,EACf,mBAAmB,EACnB,2BAA2B,EAC3B,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAiEpB;;;;;;GAMG;AACH,qBACa,oBACX,YAAW,kBAAkB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,eAAe;IAY3F,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4B;IACxD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAqB;IAChE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAC5C,OAAO,CAAC,cAAc,CAAmF;IACzG,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAA4B;gBAGhC,OAAO,EAAE,2BAA2B,EACpC,gBAAgB,EAAE,SAAS,EAC3B,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB;IAM5C;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,EAAE,OAAO,GAAE,eAAoB,GAAG,IAAI;IAuBhH;;;;;;;OAOG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,EAAE,OAAO,GAAE,mBAAwB,GAAG,IAAI;IAsBhH;;;;;;;OAOG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,EAAE,OAAO,GAAE,kBAAuB,GAAG,IAAI;IAsB9G;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAY7B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IA4B7B;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAgB9B;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS;IAMvD;;;;OAIG;IACH,MAAM,IAAI,wBAAwB,EAAE;IAIpC;;;;;OAKG;IACH,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAqC5D;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAqC1C,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBvC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC,4BAA4B;IA8B5B,OAAO,CAAC,0BAA0B;YAkBpB,QAAQ;YAYR,0CAA0C;YAQ1C,cAAc;IAQ5B,OAAO,CAAC,oCAAoC;IAQ5C,OAAO,CAAC,oBAAoB;YAOd,oBAAoB;IAmBlC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,uBAAuB;IAM/B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,qBAAqB;IAsD7B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,mBAAmB;YAQb,cAAc;YAmBd,WAAW;IASzB,OAAO,CAAC,6BAA6B;YAIvB,sBAAsB;YA0BtB,kBAAkB;YA2BlB,gBAAgB;YAMhB,WAAW;IAYzB,OAAO,CAAC,qBAAqB;CAK9B"}
|
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 ??
|
|
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
|
|
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 ??
|
|
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
|
|
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 ??
|
|
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
|
|
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 ?
|
|
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
package/dist/status.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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
|
|
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.
|
|
41
|
-
"@fluojs/di": "^1.0
|
|
42
|
-
"@fluojs/
|
|
43
|
-
|
|
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",
|