@fluojs/terminus 1.0.0-beta.5 → 1.0.0-beta.6
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 +13 -3
- package/README.md +13 -3
- package/dist/health-check.d.ts.map +1 -1
- package/dist/health-check.js +26 -1
- package/dist/indicators/disk.d.ts.map +1 -1
- package/dist/indicators/disk.js +7 -2
- package/dist/indicators/drizzle.d.ts +21 -5
- package/dist/indicators/drizzle.d.ts.map +1 -1
- package/dist/indicators/drizzle.js +53 -10
- package/dist/module.d.ts +2 -0
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +13 -14
- package/dist/node.d.ts +3 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +2 -0
- package/package.json +11 -7
package/README.ko.md
CHANGED
|
@@ -37,7 +37,8 @@ pnpm add @fluojs/terminus
|
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
39
|
import { Module } from '@fluojs/core';
|
|
40
|
-
import { HttpHealthIndicator,
|
|
40
|
+
import { HttpHealthIndicator, TerminusModule } from '@fluojs/terminus';
|
|
41
|
+
import { MemoryHealthIndicator } from '@fluojs/terminus/node';
|
|
41
42
|
|
|
42
43
|
@Module({
|
|
43
44
|
imports: [
|
|
@@ -61,8 +62,8 @@ class AppModule {}
|
|
|
61
62
|
- `PrismaHealthIndicator` / `DrizzleHealthIndicator`
|
|
62
63
|
- `RedisHealthIndicator` (`@fluojs/terminus/redis`에서 제공)
|
|
63
64
|
- `HttpHealthIndicator`
|
|
64
|
-
- `MemoryHealthIndicator`
|
|
65
|
-
- `DiskHealthIndicator`
|
|
65
|
+
- `MemoryHealthIndicator` (호환성을 위해 root에서도 export되며 `@fluojs/terminus/node`에서도 제공)
|
|
66
|
+
- `DiskHealthIndicator` (호환성을 위해 root에서도 export되며 `@fluojs/terminus/node`에서도 제공)
|
|
66
67
|
|
|
67
68
|
### DI 기반 인디케이터
|
|
68
69
|
|
|
@@ -90,6 +91,8 @@ TerminusModule.forRoot({
|
|
|
90
91
|
});
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
Drizzle의 경우 `createDrizzleHealthIndicatorProvider()`는 `@fluojs/drizzle`이 노출하는 lifecycle-aware `DrizzleDatabase` wrapper를 우선 사용합니다. Drizzle이 종료 중이거나 중지되었거나 `DrizzleDatabase.createPlatformStatusSnapshot()` 기준으로 준비되지 않은 상태이면 SQL probe를 실행하기 전에 해당 indicator를 `down`으로 보고합니다. legacy raw `DRIZZLE_DATABASE` handle만 등록된 경우에는 기존 lightweight SQL probe 동작을 유지합니다.
|
|
95
|
+
|
|
93
96
|
### 실행 가드레일
|
|
94
97
|
|
|
95
98
|
커스텀 인디케이터가 멈추거나 느린 하위 서비스에 의존할 수 있다면 `execution.indicatorTimeoutMs`를 사용하세요. probe가 설정된 시간을 넘기면 Terminus는 무기한 대기하지 않고 해당 인디케이터를 `down`으로 표시합니다.
|
|
@@ -114,9 +117,11 @@ TerminusModule.forRoot({
|
|
|
114
117
|
- 응답 본문은 `status`, `contributors`, `info`, `error`, `details`를 포함한 구조화된 JSON 객체입니다.
|
|
115
118
|
- 하나의 인디케이터가 여러 keyed entry를 반환할 수도 있으며, 이 경우 `/health`는 모든 entry를 `details`와 `contributors.up` / `contributors.down` 요약에 그대로 반영합니다.
|
|
116
119
|
- 지원하지 않는 status, 빈 결과, 객체가 아닌 인디케이터 결과는 조용히 버려지지 않고 `down` 진단으로 보고됩니다.
|
|
120
|
+
- Blank indicator result key는 healthy entry로 기여하지 않고 `down` 진단으로 보고됩니다.
|
|
117
121
|
- 같은 실행에서 이미 보고된 key를 다른 인디케이터가 다시 사용하면, Terminus는 먼저 기록된 entry를 유지하고 데이터를 조용히 덮어쓰는 대신 결정적인 `*-duplicate-key-error` contributor를 추가합니다.
|
|
118
122
|
- 플랫폼 health/readiness 실패는 `/health` 응답에서 결정적인 `fluo-platform-health`, `fluo-platform-readiness` contributor로 노출됩니다.
|
|
119
123
|
- Runtime diagnostics가 있으면 `/health` response에 platform health/readiness detail을 담은 `platform` block이 포함될 수 있습니다.
|
|
124
|
+
- DI provider로 생성한 Drizzle indicator는 SQL probe보다 먼저 Drizzle lifecycle readiness/health state를 반영하므로, underlying driver가 raw ping을 아직 받을 수 있어도 종료 중이거나 중지된 통합은 `/health`와 `/ready`를 unavailable로 표시합니다.
|
|
120
125
|
|
|
121
126
|
## 공개 API 개요
|
|
122
127
|
|
|
@@ -144,6 +149,11 @@ TerminusModule.forRoot({
|
|
|
144
149
|
- `RedisHealthIndicator`, `createRedisHealthIndicator()`, `createRedisHealthIndicatorProvider()`
|
|
145
150
|
- Redis 전용 인디케이터 헬퍼는 선택적 Redis 피어가 설치되지 않은 환경에서도 루트 패키지 import가 안전하도록 전용 subpath에서 export됩니다.
|
|
146
151
|
|
|
152
|
+
### `@fluojs/terminus/node`
|
|
153
|
+
|
|
154
|
+
- `MemoryHealthIndicator`, `DiskHealthIndicator`, `createMemoryHealthIndicator()`, `createDiskHealthIndicator()`
|
|
155
|
+
- Node 전용 indicator helper는 호환성을 위해 root에서도 계속 export되며 이 전용 subpath에서도 export됩니다. Disk check의 filesystem access는 lazy-load되므로 root package import 시점에는 Node filesystem module을 load하지 않습니다.
|
|
156
|
+
|
|
147
157
|
|
|
148
158
|
### `HealthCheckError`
|
|
149
159
|
|
package/README.md
CHANGED
|
@@ -35,7 +35,8 @@ Import `TerminusModule.forRoot()` to register health indicators.
|
|
|
35
35
|
|
|
36
36
|
```typescript
|
|
37
37
|
import { Module } from '@fluojs/core';
|
|
38
|
-
import { HttpHealthIndicator,
|
|
38
|
+
import { HttpHealthIndicator, TerminusModule } from '@fluojs/terminus';
|
|
39
|
+
import { MemoryHealthIndicator } from '@fluojs/terminus/node';
|
|
39
40
|
|
|
40
41
|
@Module({
|
|
41
42
|
imports: [
|
|
@@ -59,8 +60,8 @@ The package provides several indicators out of the box:
|
|
|
59
60
|
- `PrismaHealthIndicator` / `DrizzleHealthIndicator`
|
|
60
61
|
- `RedisHealthIndicator` (from `@fluojs/terminus/redis`)
|
|
61
62
|
- `HttpHealthIndicator`
|
|
62
|
-
- `MemoryHealthIndicator`
|
|
63
|
-
- `DiskHealthIndicator`
|
|
63
|
+
- `MemoryHealthIndicator` (root-exported for compatibility and also available from `@fluojs/terminus/node`)
|
|
64
|
+
- `DiskHealthIndicator` (root-exported for compatibility and also available from `@fluojs/terminus/node`)
|
|
64
65
|
|
|
65
66
|
### DI-Backed Indicators
|
|
66
67
|
|
|
@@ -88,6 +89,8 @@ TerminusModule.forRoot({
|
|
|
88
89
|
});
|
|
89
90
|
```
|
|
90
91
|
|
|
92
|
+
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.
|
|
93
|
+
|
|
91
94
|
### Execution Guardrails
|
|
92
95
|
|
|
93
96
|
Use `execution.indicatorTimeoutMs` when custom indicators might hang or depend on slow downstreams. When a probe exceeds the configured timeout, Terminus marks that indicator as `down` instead of waiting forever.
|
|
@@ -114,9 +117,11 @@ When an indicator fails, it throws a `HealthCheckError`. The `TerminusHealthServ
|
|
|
114
117
|
- The response body contains a structured JSON object with `status`, `contributors`, `info`, `error`, and `details`.
|
|
115
118
|
- Indicators may emit multiple keyed entries in a single check result; `/health` preserves every keyed entry in `details` and in the `contributors.up` / `contributors.down` summaries.
|
|
116
119
|
- Unsupported, empty, or non-object indicator results are reported as `down` diagnostics instead of being silently discarded.
|
|
120
|
+
- Blank indicator result keys are reported as `down` diagnostics instead of contributing healthy entries.
|
|
117
121
|
- If an indicator reuses a key that was already reported earlier in the same run, Terminus keeps the first entry and adds a deterministic `*-duplicate-key-error` contributor instead of silently overwriting data.
|
|
118
122
|
- Platform health/readiness failures are surfaced as deterministic `fluo-platform-health` and `fluo-platform-readiness` contributors in `/health` responses.
|
|
119
123
|
- `/health` responses may include a `platform` block with platform health/readiness details when runtime diagnostics are available.
|
|
124
|
+
- 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.
|
|
120
125
|
|
|
121
126
|
## Public API Overview
|
|
122
127
|
|
|
@@ -144,6 +149,11 @@ When an indicator fails, it throws a `HealthCheckError`. The `TerminusHealthServ
|
|
|
144
149
|
- `RedisHealthIndicator`, `createRedisHealthIndicator()`, `createRedisHealthIndicatorProvider()`
|
|
145
150
|
- Redis-specific indicator helpers are exported from the dedicated subpath so the root package stays import-safe without the optional Redis peer installed.
|
|
146
151
|
|
|
152
|
+
### `@fluojs/terminus/node`
|
|
153
|
+
|
|
154
|
+
- `MemoryHealthIndicator`, `DiskHealthIndicator`, `createMemoryHealthIndicator()`, `createDiskHealthIndicator()`
|
|
155
|
+
- Node-specific indicator helpers remain root-exported for compatibility and are also exported from this dedicated subpath. Filesystem access for disk checks is lazy-loaded so importing the root package does not load Node filesystem modules at module initialization time.
|
|
156
|
+
|
|
147
157
|
|
|
148
158
|
### `HealthCheckError`
|
|
149
159
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../src/health-check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,2BAA2B,EAC3B,iBAAiB,EACjB,eAAe,EAGhB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../src/health-check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,2BAA2B,EAC3B,iBAAiB,EACjB,eAAe,EAGhB,MAAM,YAAY,CAAC;AAyQpB;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,gBAAgB,GAAE,2BAAgC,GACjD,OAAO,CAAC,iBAAiB,CAAC,CAoB5B;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,SAAyB,GAAG,iBAAiB,CAMhH;AAED,0FAA0F;AAC1F,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBADhB,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,gBAAgB,GAAE,2BAAgC;IAGrE;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAIzC;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAGpC"}
|
package/dist/health-check.js
CHANGED
|
@@ -40,6 +40,25 @@ function hasIndicatorStatus(value) {
|
|
|
40
40
|
function createUnsupportedEntryMessage(entryKey) {
|
|
41
41
|
return entryKey.trim().length > 0 ? `Indicator returned an unsupported status value for result key "${entryKey}".` : 'Indicator returned an unsupported status value for an empty result key.';
|
|
42
42
|
}
|
|
43
|
+
function createBlankKeyFailureKey(indicatorKey, seenKeys) {
|
|
44
|
+
const baseKey = `${indicatorKey}-blank-key-error`;
|
|
45
|
+
if (!seenKeys.has(baseKey)) {
|
|
46
|
+
return baseKey;
|
|
47
|
+
}
|
|
48
|
+
let suffix = 2;
|
|
49
|
+
let candidate = `${baseKey}-${String(suffix)}`;
|
|
50
|
+
while (seenKeys.has(candidate)) {
|
|
51
|
+
suffix += 1;
|
|
52
|
+
candidate = `${baseKey}-${String(suffix)}`;
|
|
53
|
+
}
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
function createBlankKeyFailure(indicatorKey, seenKeys) {
|
|
57
|
+
return [createBlankKeyFailureKey(indicatorKey, seenKeys), {
|
|
58
|
+
message: 'Indicator returned a blank result key.',
|
|
59
|
+
status: 'down'
|
|
60
|
+
}];
|
|
61
|
+
}
|
|
43
62
|
function normalizeIndicatorResult(key, result) {
|
|
44
63
|
if (typeof result !== 'object' || result === null || Array.isArray(result)) {
|
|
45
64
|
return [[key, {
|
|
@@ -58,7 +77,13 @@ function normalizeIndicatorResult(key, result) {
|
|
|
58
77
|
}]];
|
|
59
78
|
}
|
|
60
79
|
for (const [entryKey, entryValue] of entries) {
|
|
61
|
-
|
|
80
|
+
if (entryKey.trim().length === 0) {
|
|
81
|
+
const blankKeyFailure = createBlankKeyFailure(key, seenKeys);
|
|
82
|
+
seenKeys.add(blankKeyFailure[0]);
|
|
83
|
+
normalizedEntries.push(blankKeyFailure);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const normalizedKey = entryKey;
|
|
62
87
|
if (seenKeys.has(normalizedKey)) {
|
|
63
88
|
duplicateKeys.push(normalizedKey);
|
|
64
89
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disk.d.ts","sourceRoot":"","sources":["../../src/indicators/disk.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"disk.d.ts","sourceRoot":"","sources":["../../src/indicators/disk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE1E,sEAAsE;AACtE,MAAM,WAAW,0BAA0B;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAcD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,0BAA+B,GAAG,eAAe,CAEnG;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,GAAE,0BAA+B,GAAG,QAAQ,CAKpG;AAED,yEAAyE;AACzE,qBAAa,mBAAoB,YAAW,eAAe;IAG7C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEJ,OAAO,GAAE,0BAA+B;IAI/D,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAsCzD"}
|
package/dist/indicators/disk.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { statfs } from 'node:fs/promises';
|
|
2
1
|
import { createDownResult, createUpResult, resolveIndicatorKey, throwHealthCheckError } from './utils.js';
|
|
3
2
|
|
|
4
3
|
/** Options for checking free disk bytes and free-ratio thresholds. */
|
|
@@ -7,6 +6,12 @@ const DEFAULT_DISK_FREE_RATIO_THRESHOLD = 0.1;
|
|
|
7
6
|
function toNumber(value) {
|
|
8
7
|
return typeof value === 'bigint' ? Number(value) : value;
|
|
9
8
|
}
|
|
9
|
+
async function statFilesystem(path) {
|
|
10
|
+
const {
|
|
11
|
+
statfs
|
|
12
|
+
} = await import('node:fs/promises');
|
|
13
|
+
return statfs(path);
|
|
14
|
+
}
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Create a disk-space health indicator.
|
|
@@ -43,7 +48,7 @@ export class DiskHealthIndicator {
|
|
|
43
48
|
const path = this.options.path ?? '.';
|
|
44
49
|
const minFreeRatio = this.options.minFreeRatio ?? DEFAULT_DISK_FREE_RATIO_THRESHOLD;
|
|
45
50
|
try {
|
|
46
|
-
const stats = await
|
|
51
|
+
const stats = await statFilesystem(path);
|
|
47
52
|
const blockSize = toNumber(stats.bsize);
|
|
48
53
|
const blocks = toNumber(stats.blocks);
|
|
49
54
|
const availableBlocks = toNumber(stats.bavail);
|
|
@@ -1,11 +1,27 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Provider } from '@fluojs/di';
|
|
2
2
|
import type { HealthIndicator, HealthIndicatorResult } from '../types.js';
|
|
3
3
|
interface DrizzleExecuteLike {
|
|
4
4
|
execute?: (query: unknown) => Promise<unknown>;
|
|
5
5
|
}
|
|
6
|
+
interface DrizzleLifecycleSnapshotLike {
|
|
7
|
+
details?: Record<string, unknown>;
|
|
8
|
+
health: {
|
|
9
|
+
reason?: string;
|
|
10
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
11
|
+
};
|
|
12
|
+
readiness: {
|
|
13
|
+
reason?: string;
|
|
14
|
+
status: 'ready' | 'not-ready';
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface DrizzleHandleProviderLike {
|
|
18
|
+
createPlatformStatusSnapshot?: () => DrizzleLifecycleSnapshotLike;
|
|
19
|
+
current?: () => DrizzleExecuteLike | unknown;
|
|
20
|
+
}
|
|
6
21
|
/** Options for probing Drizzle-backed database connectivity. */
|
|
7
22
|
export interface DrizzleHealthIndicatorOptions {
|
|
8
23
|
database?: DrizzleExecuteLike;
|
|
24
|
+
handleProvider?: DrizzleHandleProviderLike;
|
|
9
25
|
key?: string;
|
|
10
26
|
ping?: () => Promise<unknown> | unknown;
|
|
11
27
|
query?: unknown;
|
|
@@ -14,8 +30,8 @@ export interface DrizzleHealthIndicatorOptions {
|
|
|
14
30
|
/**
|
|
15
31
|
* Create a Drizzle health indicator.
|
|
16
32
|
*
|
|
17
|
-
* @param options Optional database handle, ping callback, timeout, query, and key override.
|
|
18
|
-
* @returns A health indicator that
|
|
33
|
+
* @param options Optional lifecycle-aware handle provider, database handle, ping callback, timeout, query, and key override.
|
|
34
|
+
* @returns A health indicator that checks Drizzle lifecycle state before executing a lightweight query.
|
|
19
35
|
*/
|
|
20
36
|
export declare function createDrizzleHealthIndicator(options?: DrizzleHealthIndicatorOptions): HealthIndicator;
|
|
21
37
|
/**
|
|
@@ -24,8 +40,8 @@ export declare function createDrizzleHealthIndicator(options?: DrizzleHealthIndi
|
|
|
24
40
|
* @param options Optional timeout, query override, key override, or custom ping callback.
|
|
25
41
|
* @returns A factory provider that exposes `DrizzleHealthIndicator` from the DI container.
|
|
26
42
|
*/
|
|
27
|
-
export declare function createDrizzleHealthIndicatorProvider(options?: Omit<DrizzleHealthIndicatorOptions, 'database'>): Provider;
|
|
28
|
-
/** Health indicator that
|
|
43
|
+
export declare function createDrizzleHealthIndicatorProvider(options?: Omit<DrizzleHealthIndicatorOptions, 'database' | 'handleProvider'>): Provider;
|
|
44
|
+
/** Health indicator that maps Drizzle lifecycle state and probes connectivity with an execute-capable handle. */
|
|
29
45
|
export declare class DrizzleHealthIndicator implements HealthIndicator {
|
|
30
46
|
private readonly options;
|
|
31
47
|
readonly key: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../src/indicators/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../src/indicators/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAK1E,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD;AAED,UAAU,4BAA4B;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;KAC9C,CAAC;IACF,SAAS,EAAE;QACT,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC;KAC/B,CAAC;CACH;AAED,UAAU,yBAAyB;IACjC,4BAA4B,CAAC,EAAE,MAAM,4BAA4B,CAAC;IAClE,OAAO,CAAC,EAAE,MAAM,kBAAkB,GAAG,OAAO,CAAC;CAC9C;AAED,gEAAgE;AAChE,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,cAAc,CAAC,EAAE,yBAAyB,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8DD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,GAAE,6BAAkC,GAAG,eAAe,CAEzG;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAAC,OAAO,GAAE,IAAI,CAAC,6BAA6B,EAAE,UAAU,GAAG,gBAAgB,CAAM,GAAG,QAAQ,CAgB/I;AAED,iHAAiH;AACjH,qBAAa,sBAAuB,YAAW,eAAe;IAGhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEJ,OAAO,GAAE,6BAAkC;IAIlE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAiCzD"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { optional } from '@fluojs/di';
|
|
1
2
|
import { createDownResult, createUpResult, resolveIndicatorKey, throwHealthCheckError, withIndicatorTimeout } from './utils.js';
|
|
2
3
|
const DRIZZLE_DATABASE = Symbol.for('fluo.drizzle.database');
|
|
4
|
+
const DRIZZLE_HANDLE_PROVIDER = Symbol.for('fluo.drizzle.handle-provider');
|
|
3
5
|
|
|
4
6
|
/** Options for probing Drizzle-backed database connectivity. */
|
|
5
7
|
|
|
@@ -10,18 +12,43 @@ async function runDrizzlePing(options) {
|
|
|
10
12
|
await options.ping();
|
|
11
13
|
return;
|
|
12
14
|
}
|
|
13
|
-
const database = options.database;
|
|
15
|
+
const database = options.database ?? resolveCurrentDatabase(options.handleProvider);
|
|
14
16
|
if (!database || typeof database.execute !== 'function') {
|
|
15
17
|
throw new Error('Drizzle indicator requires an execute-capable database handle or a ping callback.');
|
|
16
18
|
}
|
|
17
19
|
await database.execute(options.query ?? DEFAULT_DRIZZLE_QUERY);
|
|
18
20
|
}
|
|
21
|
+
function resolveCurrentDatabase(handleProvider) {
|
|
22
|
+
if (!handleProvider || typeof handleProvider.current !== 'function') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return handleProvider.current();
|
|
26
|
+
}
|
|
27
|
+
function createDrizzleLifecycleDownResult(indicatorKey, snapshot) {
|
|
28
|
+
const healthStatus = snapshot.health.status;
|
|
29
|
+
const readinessStatus = snapshot.readiness.status;
|
|
30
|
+
if (healthStatus === 'healthy' && readinessStatus === 'ready') {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const message = snapshot.readiness.reason ?? snapshot.health.reason ?? `Drizzle lifecycle reported health=${healthStatus} readiness=${readinessStatus}.`;
|
|
34
|
+
return createDownResult(indicatorKey, message, {
|
|
35
|
+
details: snapshot.details,
|
|
36
|
+
healthStatus,
|
|
37
|
+
readinessStatus
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function createDrizzleLifecycleSnapshot(handleProvider) {
|
|
41
|
+
if (!handleProvider || typeof handleProvider.createPlatformStatusSnapshot !== 'function') {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
return handleProvider.createPlatformStatusSnapshot();
|
|
45
|
+
}
|
|
19
46
|
|
|
20
47
|
/**
|
|
21
48
|
* Create a Drizzle health indicator.
|
|
22
49
|
*
|
|
23
|
-
* @param options Optional database handle, ping callback, timeout, query, and key override.
|
|
24
|
-
* @returns A health indicator that
|
|
50
|
+
* @param options Optional lifecycle-aware handle provider, database handle, ping callback, timeout, query, and key override.
|
|
51
|
+
* @returns A health indicator that checks Drizzle lifecycle state before executing a lightweight query.
|
|
25
52
|
*/
|
|
26
53
|
export function createDrizzleHealthIndicator(options = {}) {
|
|
27
54
|
return new DrizzleHealthIndicator(options);
|
|
@@ -35,16 +62,20 @@ export function createDrizzleHealthIndicator(options = {}) {
|
|
|
35
62
|
*/
|
|
36
63
|
export function createDrizzleHealthIndicatorProvider(options = {}) {
|
|
37
64
|
return {
|
|
38
|
-
inject: [DRIZZLE_DATABASE],
|
|
65
|
+
inject: [optional(DRIZZLE_HANDLE_PROVIDER), optional(DRIZZLE_DATABASE)],
|
|
39
66
|
provide: DrizzleHealthIndicator,
|
|
40
|
-
useFactory: database =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
useFactory: (handleProvider, database) => {
|
|
68
|
+
const resolvedHandleProvider = typeof handleProvider === 'object' && handleProvider !== null ? handleProvider : undefined;
|
|
69
|
+
return new DrizzleHealthIndicator({
|
|
70
|
+
...options,
|
|
71
|
+
database: database,
|
|
72
|
+
handleProvider: resolvedHandleProvider
|
|
73
|
+
});
|
|
74
|
+
}
|
|
44
75
|
};
|
|
45
76
|
}
|
|
46
77
|
|
|
47
|
-
/** Health indicator that
|
|
78
|
+
/** Health indicator that maps Drizzle lifecycle state and probes connectivity with an execute-capable handle. */
|
|
48
79
|
export class DrizzleHealthIndicator {
|
|
49
80
|
key;
|
|
50
81
|
constructor(options = {}) {
|
|
@@ -55,9 +86,21 @@ export class DrizzleHealthIndicator {
|
|
|
55
86
|
const indicatorKey = resolveIndicatorKey('drizzle', this.options.key ?? key);
|
|
56
87
|
const timeoutMs = this.options.timeoutMs ?? DEFAULT_DRIZZLE_TIMEOUT_MS;
|
|
57
88
|
try {
|
|
89
|
+
const snapshot = createDrizzleLifecycleSnapshot(this.options.handleProvider);
|
|
90
|
+
const lifecycleDownResult = snapshot ? createDrizzleLifecycleDownResult(indicatorKey, snapshot) : undefined;
|
|
91
|
+
if (lifecycleDownResult) {
|
|
92
|
+
throwHealthCheckError('Drizzle health check failed.', lifecycleDownResult);
|
|
93
|
+
}
|
|
58
94
|
await withIndicatorTimeout(runDrizzlePing(this.options), timeoutMs, indicatorKey);
|
|
59
|
-
return createUpResult(indicatorKey
|
|
95
|
+
return createUpResult(indicatorKey, snapshot ? {
|
|
96
|
+
details: snapshot.details,
|
|
97
|
+
healthStatus: snapshot.health.status,
|
|
98
|
+
readinessStatus: snapshot.readiness.status
|
|
99
|
+
} : {});
|
|
60
100
|
} catch (error) {
|
|
101
|
+
if (error instanceof Error && error.name === 'HealthCheckError') {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
61
104
|
throwHealthCheckError('Drizzle health check failed.', createDownResult(indicatorKey, error instanceof Error ? error.message : 'Drizzle health check failed.'));
|
|
62
105
|
}
|
|
63
106
|
}
|
package/dist/module.d.ts
CHANGED
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,UAAU,EAIhB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAA4D,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAyQlH,uFAAuF;AACvF,qBAAa,cAAc;IACzB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,qBAA0B,GAAG,UAAU;CAGhE"}
|
package/dist/module.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PLATFORM_SHELL, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
|
|
1
|
+
import { defineModule, HealthModule, PLATFORM_SHELL } from '@fluojs/runtime';
|
|
3
2
|
import { TerminusHealthService } from './health-check.js';
|
|
4
3
|
import { TERMINUS_HEALTH_INDICATORS, TERMINUS_INDICATOR_PROVIDER_TOKENS } from './tokens.js';
|
|
5
4
|
const TERMINUS_OPTIONS = Symbol.for('fluo.terminus.options');
|
|
@@ -37,18 +36,16 @@ function createTerminusProviders(options = {}) {
|
|
|
37
36
|
provide: TERMINUS_INDICATOR_PROVIDER_TOKENS,
|
|
38
37
|
useValue: indicatorProviderTokens
|
|
39
38
|
}, {
|
|
40
|
-
inject: [TERMINUS_OPTIONS,
|
|
39
|
+
inject: [TERMINUS_OPTIONS, ...indicatorProviderTokens],
|
|
41
40
|
provide: TERMINUS_HEALTH_INDICATORS,
|
|
42
|
-
useFactory:
|
|
41
|
+
useFactory: (resolvedOptions, ...resolvedProviderIndicators) => {
|
|
43
42
|
const resolvedIndicators = [];
|
|
44
43
|
if (typeof resolvedOptions === 'object' && resolvedOptions !== null && 'indicators' in resolvedOptions) {
|
|
45
44
|
const indicators = resolvedOptions.indicators;
|
|
46
45
|
resolvedIndicators.push(...copyIndicators(indicators));
|
|
47
46
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
resolvedIndicators.push(await runtimeContainer.resolve(token));
|
|
51
|
-
}
|
|
47
|
+
for (const providerIndicator of resolvedProviderIndicators) {
|
|
48
|
+
resolvedIndicators.push(providerIndicator);
|
|
52
49
|
}
|
|
53
50
|
return resolvedIndicators;
|
|
54
51
|
}
|
|
@@ -143,7 +140,7 @@ function withPlatformDiagnostics(report, health, readiness) {
|
|
|
143
140
|
}
|
|
144
141
|
function createTerminusRuntimeModule(options = {}) {
|
|
145
142
|
const readinessChecks = [...(options.readinessChecks ?? [])];
|
|
146
|
-
const healthModule =
|
|
143
|
+
const healthModule = HealthModule.forRoot({
|
|
147
144
|
healthCheck: async ctx => {
|
|
148
145
|
const healthService = await ctx.container.resolve(TerminusHealthService);
|
|
149
146
|
const platformShell = await ctx.container.resolve(PLATFORM_SHELL);
|
|
@@ -171,14 +168,14 @@ function createTerminusRuntimeModule(options = {}) {
|
|
|
171
168
|
path: options.path,
|
|
172
169
|
readinessChecks
|
|
173
170
|
}), {
|
|
174
|
-
inject: [TerminusHealthService
|
|
171
|
+
inject: [TerminusHealthService],
|
|
175
172
|
provide: TERMINUS_READINESS_REGISTRAR,
|
|
176
|
-
useFactory:
|
|
177
|
-
const
|
|
173
|
+
useFactory: resolvedHealthService => {
|
|
174
|
+
const healthService = resolvedHealthService;
|
|
178
175
|
return {
|
|
179
176
|
onApplicationBootstrap() {
|
|
180
|
-
healthModule.addReadinessCheck(async
|
|
181
|
-
const platformShell = await
|
|
177
|
+
healthModule.addReadinessCheck(async ctx => {
|
|
178
|
+
const platformShell = await ctx.container.resolve(PLATFORM_SHELL);
|
|
182
179
|
const [indicatorHealthy, readiness] = await Promise.all([healthService.isHealthy(), platformShell.ready()]);
|
|
183
180
|
return indicatorHealthy && readiness.status === 'ready';
|
|
184
181
|
});
|
|
@@ -196,6 +193,8 @@ export class TerminusModule {
|
|
|
196
193
|
*
|
|
197
194
|
* @example
|
|
198
195
|
* ```ts
|
|
196
|
+
* import { MemoryHealthIndicator } from '@fluojs/terminus/node';
|
|
197
|
+
*
|
|
199
198
|
* TerminusModule.forRoot({
|
|
200
199
|
* indicators: [new MemoryHealthIndicator({ key: 'memory' })],
|
|
201
200
|
* });
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}
|
package/dist/node.js
ADDED
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"liveness",
|
|
10
10
|
"health-check"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.6",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"types": "./dist/index.d.ts",
|
|
30
30
|
"import": "./dist/index.js"
|
|
31
31
|
},
|
|
32
|
+
"./node": {
|
|
33
|
+
"types": "./dist/node.d.ts",
|
|
34
|
+
"import": "./dist/node.js"
|
|
35
|
+
},
|
|
32
36
|
"./redis": {
|
|
33
37
|
"types": "./dist/redis.d.ts",
|
|
34
38
|
"import": "./dist/redis.js"
|
|
@@ -40,15 +44,15 @@
|
|
|
40
44
|
"dist"
|
|
41
45
|
],
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@fluojs/
|
|
44
|
-
"@fluojs/di": "^1.0.0-beta.6",
|
|
47
|
+
"@fluojs/runtime": "^1.0.0-beta.12",
|
|
45
48
|
"@fluojs/http": "^1.0.0-beta.10",
|
|
46
|
-
"@fluojs/
|
|
49
|
+
"@fluojs/core": "^1.0.0-beta.5",
|
|
50
|
+
"@fluojs/di": "^1.0.0-beta.7"
|
|
47
51
|
},
|
|
48
52
|
"peerDependencies": {
|
|
49
|
-
"@fluojs/prisma": "^1.0.0-beta.
|
|
50
|
-
"@fluojs/
|
|
51
|
-
"@fluojs/
|
|
53
|
+
"@fluojs/prisma": "^1.0.0-beta.5",
|
|
54
|
+
"@fluojs/drizzle": "^1.0.0-beta.4",
|
|
55
|
+
"@fluojs/redis": "^1.0.0-beta.4"
|
|
52
56
|
},
|
|
53
57
|
"peerDependenciesMeta": {
|
|
54
58
|
"@fluojs/drizzle": {
|