@fluojs/terminus 1.0.1 → 1.0.3
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 +10 -0
- package/README.md +10 -0
- package/dist/indicators/redis.d.ts +23 -5
- package/dist/indicators/redis.d.ts.map +1 -1
- package/dist/indicators/redis.js +59 -7
- package/package.json +8 -8
package/README.ko.md
CHANGED
|
@@ -24,6 +24,12 @@ fluo 애플리케이션을 위한 헬스 인디케이터(Health Indicator) 툴
|
|
|
24
24
|
pnpm add @fluojs/terminus
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
Redis indicator subpath를 사용할 때만 선택적 peer를 설치하세요.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add @fluojs/redis ioredis
|
|
31
|
+
```
|
|
32
|
+
|
|
27
33
|
`path`로 health endpoint를 custom path 아래에 mount할 수 있고, `readinessChecks`로 애플리케이션별 readiness logic을 Terminus indicator 및 platform readiness check와 합성할 수 있습니다.
|
|
28
34
|
|
|
29
35
|
## 사용 시점
|
|
@@ -92,6 +98,8 @@ TerminusModule.forRoot({
|
|
|
92
98
|
});
|
|
93
99
|
```
|
|
94
100
|
|
|
101
|
+
`@fluojs/terminus/redis`를 통해 만든 Redis indicator는 `@fluojs/redis`에서 받은 client가 있으면 lifecycle-aware로 동작합니다. Terminus는 `PING`을 보내기 전에 Redis connection state를 `createRedisPlatformStatusSnapshot(...)`으로 매핑하므로, client가 `wait`, `connecting`, `reconnecting`, `close`, `end` 상태이면 raw ping만 믿지 않고 `/health`와 `/ready`를 unavailable로 표시합니다. Custom `ping` callback은 manual probe용으로 계속 지원되지만, lifecycle metadata는 Redis client가 `status`를 노출할 때만 붙습니다.
|
|
102
|
+
|
|
95
103
|
Drizzle의 경우 `createDrizzleHealthIndicatorProvider()`는 `@fluojs/drizzle`이 노출하는 lifecycle-aware `DrizzleDatabase` wrapper를 우선 사용합니다. Drizzle이 종료 중이거나 중지되었거나 `DrizzleDatabase.createPlatformStatusSnapshot()` 기준으로 준비되지 않은 상태이면 SQL probe를 실행하기 전에 해당 indicator를 `down`으로 보고합니다. legacy raw `DRIZZLE_DATABASE` handle만 등록된 경우에는 기존 lightweight SQL probe 동작을 유지합니다.
|
|
96
104
|
|
|
97
105
|
Provider factory는 반복 등록할 수 있습니다. 각 인스턴스가 서로 다른 indicator key나 dependency option을 사용한다면 같은 factory가 만든 provider 여러 개를 하나의 `indicatorProviders` 배열에 등록할 수 있으며, Terminus는 나중에 등록된 같은 타입 provider가 앞선 provider를 덮어쓰지 않도록 각 provider 인스턴스를 별도 DI token으로 보관합니다.
|
|
@@ -125,6 +133,7 @@ TerminusModule.forRoot({
|
|
|
125
133
|
- 플랫폼 health/readiness 실패는 `/health` 응답에서 결정적인 `fluo-platform-health`, `fluo-platform-readiness` contributor로 노출됩니다.
|
|
126
134
|
- Runtime diagnostics가 있으면 `/health` response에 platform health/readiness detail을 담은 `platform` block이 포함될 수 있습니다.
|
|
127
135
|
- DI provider로 생성한 Drizzle indicator는 SQL probe보다 먼저 Drizzle lifecycle readiness/health state를 반영하므로, underlying driver가 raw ping을 아직 받을 수 있어도 종료 중이거나 중지된 통합은 `/health`와 `/ready`를 unavailable로 표시합니다.
|
|
136
|
+
- Redis subpath로 생성한 Redis indicator는 `PING` 전에 `@fluojs/redis` client lifecycle state를 반영하므로, 종료 중이거나 연결이 끊긴 Redis client는 command 실행 전에도 `/health`와 `/ready`를 unavailable로 표시합니다.
|
|
128
137
|
|
|
129
138
|
## 공개 API 개요
|
|
130
139
|
|
|
@@ -151,6 +160,7 @@ TerminusModule.forRoot({
|
|
|
151
160
|
|
|
152
161
|
- `RedisHealthIndicator`, `createRedisHealthIndicator()`, `createRedisHealthIndicatorProvider()`
|
|
153
162
|
- Redis 전용 인디케이터 헬퍼는 선택적 Redis 피어가 설치되지 않은 환경에서도 루트 패키지 import가 안전하도록 전용 subpath에서 export됩니다.
|
|
163
|
+
- Provider는 기본적으로 default `@fluojs/redis` client token을 resolve하고, `clientName`이 있으면 named token을 resolve하며, Redis platform status semantics를 readiness 진단에 재사용합니다.
|
|
154
164
|
|
|
155
165
|
### `@fluojs/terminus/node`
|
|
156
166
|
|
package/README.md
CHANGED
|
@@ -24,6 +24,12 @@ Health indicator toolkit for fluo applications. `@fluojs/terminus` layers on top
|
|
|
24
24
|
pnpm add @fluojs/terminus
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
Install the optional peer only when you use the Redis indicator subpath:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add @fluojs/redis ioredis
|
|
31
|
+
```
|
|
32
|
+
|
|
27
33
|
## When to Use
|
|
28
34
|
|
|
29
35
|
- When you need to monitor external dependencies (databases, Redis, APIs) as part of your application's health status.
|
|
@@ -90,6 +96,8 @@ TerminusModule.forRoot({
|
|
|
90
96
|
});
|
|
91
97
|
```
|
|
92
98
|
|
|
99
|
+
Redis indicators created through `@fluojs/terminus/redis` are lifecycle-aware when they receive a client from `@fluojs/redis`. Terminus maps the Redis connection state with `createRedisPlatformStatusSnapshot(...)` before sending `PING`, so clients in `wait`, `connecting`, `reconnecting`, `close`, or `end` states mark `/health` and `/ready` unavailable instead of relying on a raw ping alone. Custom `ping` callbacks remain supported for manual probes, but lifecycle metadata is only attached when a Redis client exposes its `status`.
|
|
100
|
+
|
|
93
101
|
For Drizzle, `createDrizzleHealthIndicatorProvider()` prefers the lifecycle-aware `DrizzleDatabase` wrapper exported by `@fluojs/drizzle`. The indicator reports `down` before probing SQL whenever Drizzle is shutting down, stopped, or otherwise not ready according to `DrizzleDatabase.createPlatformStatusSnapshot()`. If only the legacy raw `DRIZZLE_DATABASE` handle is registered, the provider keeps the previous lightweight SQL probe behavior.
|
|
94
102
|
|
|
95
103
|
Provider factories are repeatable. You may register multiple providers created by the same factory in one `indicatorProviders` array when each instance uses a distinct indicator key or dependency option; Terminus keeps every provider instance under its own DI token instead of letting later same-type providers overwrite earlier ones.
|
|
@@ -125,6 +133,7 @@ When an indicator fails, it throws a `HealthCheckError`. The `TerminusHealthServ
|
|
|
125
133
|
- Platform health/readiness failures are surfaced as deterministic `fluo-platform-health` and `fluo-platform-readiness` contributors in `/health` responses.
|
|
126
134
|
- `/health` responses may include a `platform` block with platform health/readiness details when runtime diagnostics are available.
|
|
127
135
|
- Drizzle indicators created through the DI provider map Drizzle lifecycle readiness/health state before SQL probing, so shutdown or stopped integrations mark `/health` and `/ready` as unavailable even if the underlying driver still accepts a raw ping.
|
|
136
|
+
- Redis indicators created through the Redis subpath map `@fluojs/redis` client lifecycle state before `PING`, so shutdown or disconnected Redis clients mark `/health` and `/ready` as unavailable even before command execution.
|
|
128
137
|
|
|
129
138
|
## Public API Overview
|
|
130
139
|
|
|
@@ -151,6 +160,7 @@ When an indicator fails, it throws a `HealthCheckError`. The `TerminusHealthServ
|
|
|
151
160
|
|
|
152
161
|
- `RedisHealthIndicator`, `createRedisHealthIndicator()`, `createRedisHealthIndicatorProvider()`
|
|
153
162
|
- Redis-specific indicator helpers are exported from the dedicated subpath so the root package stays import-safe without the optional Redis peer installed.
|
|
163
|
+
- The provider resolves the default `@fluojs/redis` client token by default, or a named token when `clientName` is supplied, and reuses Redis platform status semantics for readiness diagnostics.
|
|
154
164
|
|
|
155
165
|
### `@fluojs/terminus/node`
|
|
156
166
|
|
|
@@ -1,31 +1,49 @@
|
|
|
1
1
|
import type { Provider } from '@fluojs/di';
|
|
2
|
+
import { type RedisStatusAdapterInput } from '@fluojs/redis';
|
|
2
3
|
import type { HealthIndicator, HealthIndicatorResult } from '../types.js';
|
|
3
4
|
interface RedisClientLike {
|
|
4
5
|
ping?: () => Promise<unknown>;
|
|
6
|
+
status?: RedisStatusAdapterInput['status'];
|
|
5
7
|
}
|
|
6
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Options for probing Redis connectivity.
|
|
10
|
+
*
|
|
11
|
+
* `client` may be a raw `ioredis`-compatible handle resolved from `@fluojs/redis`.
|
|
12
|
+
* When that handle exposes a Redis `status`, Terminus maps the lifecycle state into
|
|
13
|
+
* health/readiness metadata before issuing `PING`, so shutdown or disconnected clients
|
|
14
|
+
* fail readiness even if a raw ping callback would still be callable.
|
|
15
|
+
*/
|
|
7
16
|
export interface RedisHealthIndicatorOptions {
|
|
17
|
+
/** Raw Redis client to probe. Its `status` is used for lifecycle-aware readiness when available. */
|
|
8
18
|
client?: RedisClientLike;
|
|
19
|
+
/** Named Redis registration to resolve when using `createRedisHealthIndicatorProvider(...)`. */
|
|
9
20
|
clientName?: string;
|
|
21
|
+
/** Indicator result key override. Defaults to the key passed to `check(...)`, then `redis`. */
|
|
10
22
|
key?: string;
|
|
23
|
+
/** Custom ping callback for manual probes or tests. Lifecycle state is only mapped when `client.status` is available. */
|
|
11
24
|
ping?: () => Promise<unknown> | unknown;
|
|
25
|
+
/** Maximum time to wait for the ping operation. Defaults to `2_000` ms. */
|
|
12
26
|
timeoutMs?: number;
|
|
13
27
|
}
|
|
14
28
|
/**
|
|
15
29
|
* Create a Redis health indicator.
|
|
16
30
|
*
|
|
17
|
-
* @param options Optional Redis client, ping callback, timeout, and key override.
|
|
18
|
-
* @returns A health indicator that checks Redis
|
|
31
|
+
* @param options Optional Redis client, named-client hint, ping callback, timeout, and key override.
|
|
32
|
+
* @returns A health indicator that checks Redis lifecycle status before `PING` when client state is available.
|
|
19
33
|
*/
|
|
20
34
|
export declare function createRedisHealthIndicator(options?: RedisHealthIndicatorOptions): HealthIndicator;
|
|
21
35
|
/**
|
|
22
36
|
* Create a provider that resolves a Redis client from DI and wraps it as an indicator.
|
|
23
37
|
*
|
|
24
|
-
*
|
|
38
|
+
* The provider resolves `getRedisClientToken(options.clientName)`, preserving the
|
|
39
|
+
* default-vs-named client lifecycle boundary from `@fluojs/redis` while keeping the
|
|
40
|
+
* Redis-specific peer dependency isolated to `@fluojs/terminus/redis`.
|
|
41
|
+
*
|
|
42
|
+
* @param options Optional named-client hint, timeout, key override, or custom ping callback.
|
|
25
43
|
* @returns A factory provider that exposes `RedisHealthIndicator` from the DI container.
|
|
26
44
|
*/
|
|
27
45
|
export declare function createRedisHealthIndicatorProvider(options?: Omit<RedisHealthIndicatorOptions, 'client'>): Provider;
|
|
28
|
-
/** Health indicator that
|
|
46
|
+
/** Health indicator that maps Redis lifecycle status and checks reachability with a ping-like operation. */
|
|
29
47
|
export declare class RedisHealthIndicator implements HealthIndicator {
|
|
30
48
|
private readonly options;
|
|
31
49
|
readonly key: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/indicators/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/indicators/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAA+E,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAG1I,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE1E,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;CAC5C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,2BAA2B;IAC1C,oGAAoG;IACpG,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yHAAyH;IACzH,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,2BAAgC,GAAG,eAAe,CAErG;AAED;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,GAAE,IAAI,CAAC,2BAA2B,EAAE,QAAQ,CAAM,GAAG,QAAQ,CAQtH;AAED,4GAA4G;AAC5G,qBAAa,oBAAqB,YAAW,eAAe;IAG9C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEJ,OAAO,GAAE,2BAAgC;IAIhE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAwBzD"}
|
package/dist/indicators/redis.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { getRedisClientToken } from '@fluojs/redis';
|
|
1
|
+
import { createRedisPlatformStatusSnapshot, getRedisClientToken, getRedisComponentId } from '@fluojs/redis';
|
|
2
2
|
import { createDownResult, createUpResult, resolveIndicatorKey, throwHealthCheckError, withIndicatorTimeout } from './utils.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Options for probing Redis connectivity.
|
|
6
|
+
*
|
|
7
|
+
* `client` may be a raw `ioredis`-compatible handle resolved from `@fluojs/redis`.
|
|
8
|
+
* When that handle exposes a Redis `status`, Terminus maps the lifecycle state into
|
|
9
|
+
* health/readiness metadata before issuing `PING`, so shutdown or disconnected clients
|
|
10
|
+
* fail readiness even if a raw ping callback would still be callable.
|
|
11
|
+
*/
|
|
5
12
|
|
|
6
13
|
const DEFAULT_REDIS_TIMEOUT_MS = 2_000;
|
|
7
14
|
async function runRedisPing(options) {
|
|
@@ -15,12 +22,46 @@ async function runRedisPing(options) {
|
|
|
15
22
|
}
|
|
16
23
|
await client.ping();
|
|
17
24
|
}
|
|
25
|
+
function createRedisLifecycleDownResult(indicatorKey, options) {
|
|
26
|
+
const status = options.client?.status;
|
|
27
|
+
if (!status) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const snapshot = createRedisPlatformStatusSnapshot({
|
|
31
|
+
componentId: getRedisComponentId(options.clientName),
|
|
32
|
+
status
|
|
33
|
+
});
|
|
34
|
+
if (snapshot.health.status === 'healthy' && snapshot.readiness.status === 'ready') {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const message = snapshot.readiness.reason ?? snapshot.health.reason ?? `Redis lifecycle reported health=${snapshot.health.status} readiness=${snapshot.readiness.status}.`;
|
|
38
|
+
return createDownResult(indicatorKey, message, {
|
|
39
|
+
details: snapshot.details,
|
|
40
|
+
healthStatus: snapshot.health.status,
|
|
41
|
+
readinessStatus: snapshot.readiness.status
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function createRedisLifecycleUpDetails(options) {
|
|
45
|
+
const status = options.client?.status;
|
|
46
|
+
if (!status) {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
const snapshot = createRedisPlatformStatusSnapshot({
|
|
50
|
+
componentId: getRedisComponentId(options.clientName),
|
|
51
|
+
status
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
details: snapshot.details,
|
|
55
|
+
healthStatus: snapshot.health.status,
|
|
56
|
+
readinessStatus: snapshot.readiness.status
|
|
57
|
+
};
|
|
58
|
+
}
|
|
18
59
|
|
|
19
60
|
/**
|
|
20
61
|
* Create a Redis health indicator.
|
|
21
62
|
*
|
|
22
|
-
* @param options Optional Redis client, ping callback, timeout, and key override.
|
|
23
|
-
* @returns A health indicator that checks Redis
|
|
63
|
+
* @param options Optional Redis client, named-client hint, ping callback, timeout, and key override.
|
|
64
|
+
* @returns A health indicator that checks Redis lifecycle status before `PING` when client state is available.
|
|
24
65
|
*/
|
|
25
66
|
export function createRedisHealthIndicator(options = {}) {
|
|
26
67
|
return new RedisHealthIndicator(options);
|
|
@@ -29,7 +70,11 @@ export function createRedisHealthIndicator(options = {}) {
|
|
|
29
70
|
/**
|
|
30
71
|
* Create a provider that resolves a Redis client from DI and wraps it as an indicator.
|
|
31
72
|
*
|
|
32
|
-
*
|
|
73
|
+
* The provider resolves `getRedisClientToken(options.clientName)`, preserving the
|
|
74
|
+
* default-vs-named client lifecycle boundary from `@fluojs/redis` while keeping the
|
|
75
|
+
* Redis-specific peer dependency isolated to `@fluojs/terminus/redis`.
|
|
76
|
+
*
|
|
77
|
+
* @param options Optional named-client hint, timeout, key override, or custom ping callback.
|
|
33
78
|
* @returns A factory provider that exposes `RedisHealthIndicator` from the DI container.
|
|
34
79
|
*/
|
|
35
80
|
export function createRedisHealthIndicatorProvider(options = {}) {
|
|
@@ -44,7 +89,7 @@ export function createRedisHealthIndicatorProvider(options = {}) {
|
|
|
44
89
|
};
|
|
45
90
|
}
|
|
46
91
|
|
|
47
|
-
/** Health indicator that
|
|
92
|
+
/** Health indicator that maps Redis lifecycle status and checks reachability with a ping-like operation. */
|
|
48
93
|
export class RedisHealthIndicator {
|
|
49
94
|
key;
|
|
50
95
|
constructor(options = {}) {
|
|
@@ -55,9 +100,16 @@ export class RedisHealthIndicator {
|
|
|
55
100
|
const indicatorKey = resolveIndicatorKey('redis', this.options.key ?? key);
|
|
56
101
|
const timeoutMs = this.options.timeoutMs ?? DEFAULT_REDIS_TIMEOUT_MS;
|
|
57
102
|
try {
|
|
103
|
+
const lifecycleDownResult = createRedisLifecycleDownResult(indicatorKey, this.options);
|
|
104
|
+
if (lifecycleDownResult) {
|
|
105
|
+
throwHealthCheckError('Redis health check failed.', lifecycleDownResult);
|
|
106
|
+
}
|
|
58
107
|
await withIndicatorTimeout(runRedisPing(this.options), timeoutMs, indicatorKey);
|
|
59
|
-
return createUpResult(indicatorKey);
|
|
108
|
+
return createUpResult(indicatorKey, createRedisLifecycleUpDetails(this.options));
|
|
60
109
|
} catch (error) {
|
|
110
|
+
if (error instanceof Error && error.name === 'HealthCheckError') {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
61
113
|
throwHealthCheckError('Redis health check failed.', createDownResult(indicatorKey, error instanceof Error ? error.message : 'Redis health check failed.'));
|
|
62
114
|
}
|
|
63
115
|
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"liveness",
|
|
10
10
|
"health-check"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.
|
|
12
|
+
"version": "1.0.3",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"dist"
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@fluojs/core": "^1.0.
|
|
48
|
-
"@fluojs/di": "^1.0.
|
|
49
|
-
"@fluojs/http": "^1.
|
|
50
|
-
"@fluojs/runtime": "^1.
|
|
47
|
+
"@fluojs/core": "^1.0.3",
|
|
48
|
+
"@fluojs/di": "^1.0.3",
|
|
49
|
+
"@fluojs/http": "^1.1.0",
|
|
50
|
+
"@fluojs/runtime": "^1.1.1"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@fluojs/drizzle": "^1.0.
|
|
54
|
-
"@fluojs/prisma": "^1.0.
|
|
53
|
+
"@fluojs/drizzle": "^1.0.1",
|
|
54
|
+
"@fluojs/prisma": "^1.0.1",
|
|
55
55
|
"@fluojs/redis": "^1.0.0"
|
|
56
56
|
},
|
|
57
57
|
"peerDependenciesMeta": {
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"vitest": "^3.2.4",
|
|
70
|
-
"@fluojs/testing": "^1.0.
|
|
70
|
+
"@fluojs/testing": "^1.0.3"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|