@fluojs/terminus 1.0.0-beta.1 → 1.0.0-beta.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 +2 -0
- package/README.md +2 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/health-check.d.ts.map +1 -1
- package/dist/health-check.js +39 -9
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +82 -10
- package/package.json +8 -8
package/README.ko.md
CHANGED
|
@@ -111,7 +111,9 @@ TerminusModule.forRoot({
|
|
|
111
111
|
- 준비 상태(readiness)와 관련된 인디케이터가 실패하면 `/ready`는 HTTP `503`을 반환합니다.
|
|
112
112
|
- 응답 본문은 `status`, `contributors`, `info`, `error`, `details`를 포함한 구조화된 JSON 객체입니다.
|
|
113
113
|
- 하나의 인디케이터가 여러 keyed entry를 반환할 수도 있으며, 이 경우 `/health`는 모든 entry를 `details`와 `contributors.up` / `contributors.down` 요약에 그대로 반영합니다.
|
|
114
|
+
- 지원하지 않는 status, 빈 결과, 객체가 아닌 인디케이터 결과는 조용히 버려지지 않고 `down` 진단으로 보고됩니다.
|
|
114
115
|
- 같은 실행에서 이미 보고된 key를 다른 인디케이터가 다시 사용하면, Terminus는 먼저 기록된 entry를 유지하고 데이터를 조용히 덮어쓰는 대신 결정적인 `*-duplicate-key-error` contributor를 추가합니다.
|
|
116
|
+
- 플랫폼 health/readiness 실패는 `/health` 응답에서 결정적인 `fluo-platform-health`, `fluo-platform-readiness` contributor로 노출됩니다.
|
|
115
117
|
|
|
116
118
|
## 공개 API 개요
|
|
117
119
|
|
package/README.md
CHANGED
|
@@ -111,7 +111,9 @@ When an indicator fails, it throws a `HealthCheckError`. The `TerminusHealthServ
|
|
|
111
111
|
- `/ready` returns HTTP `503` if any indicator associated with readiness fails.
|
|
112
112
|
- The response body contains a structured JSON object with `status`, `contributors`, `info`, `error`, and `details`.
|
|
113
113
|
- 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.
|
|
114
|
+
- Unsupported, empty, or non-object indicator results are reported as `down` diagnostics instead of being silently discarded.
|
|
114
115
|
- 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.
|
|
116
|
+
- Platform health/readiness failures are surfaced as deterministic `fluo-platform-health` and `fluo-platform-readiness` contributors in `/health` responses.
|
|
115
117
|
|
|
116
118
|
## Public API Overview
|
|
117
119
|
|
package/dist/errors.d.ts
CHANGED
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;gBAE3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB;CAK3D"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;gBAE3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB;CAK3D"}
|
package/dist/errors.js
CHANGED
|
@@ -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;AAsOpB;;;;;;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
|
@@ -37,17 +37,47 @@ function hasIndicatorStatus(value) {
|
|
|
37
37
|
const status = value.status;
|
|
38
38
|
return status === 'up' || status === 'down';
|
|
39
39
|
}
|
|
40
|
+
function createUnsupportedEntryMessage(entryKey) {
|
|
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
|
+
}
|
|
40
43
|
function normalizeIndicatorResult(key, result) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
if (typeof result !== 'object' || result === null || Array.isArray(result)) {
|
|
45
|
+
return [[key, {
|
|
46
|
+
message: 'Indicator returned a non-object health result.',
|
|
47
|
+
status: 'down'
|
|
48
|
+
}]];
|
|
44
49
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
const normalizedEntries = [];
|
|
51
|
+
const seenKeys = new Set();
|
|
52
|
+
const duplicateKeys = [];
|
|
53
|
+
const entries = Object.entries(result);
|
|
54
|
+
if (entries.length === 0) {
|
|
55
|
+
return [[key, {
|
|
56
|
+
message: 'Indicator returned no health result entries.',
|
|
48
57
|
status: 'down'
|
|
58
|
+
}]];
|
|
59
|
+
}
|
|
60
|
+
for (const [entryKey, entryValue] of entries) {
|
|
61
|
+
const normalizedKey = hasIndicatorStatus(entryValue) || entryKey.trim().length > 0 ? entryKey : key;
|
|
62
|
+
if (seenKeys.has(normalizedKey)) {
|
|
63
|
+
duplicateKeys.push(normalizedKey);
|
|
64
|
+
continue;
|
|
49
65
|
}
|
|
50
|
-
|
|
66
|
+
seenKeys.add(normalizedKey);
|
|
67
|
+
if (hasIndicatorStatus(entryValue)) {
|
|
68
|
+
normalizedEntries.push([normalizedKey, entryValue]);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
normalizedEntries.push([normalizedKey, {
|
|
72
|
+
message: createUnsupportedEntryMessage(entryKey),
|
|
73
|
+
status: 'down'
|
|
74
|
+
}]);
|
|
75
|
+
}
|
|
76
|
+
if (duplicateKeys.length > 0) {
|
|
77
|
+
const duplicateFailure = createDuplicateKeyFailure(key, duplicateKeys, seenKeys);
|
|
78
|
+
normalizedEntries.push(duplicateFailure);
|
|
79
|
+
}
|
|
80
|
+
return normalizedEntries;
|
|
51
81
|
}
|
|
52
82
|
function inferIndicatorKey(indicator, index) {
|
|
53
83
|
const candidateKey = indicator.key;
|
|
@@ -85,13 +115,13 @@ async function runIndicator(indicator, index, executionOptions) {
|
|
|
85
115
|
try {
|
|
86
116
|
const result = indicatorTimeoutMs === undefined ? await indicator.check(key) : await withTimeout(indicator.check(key), indicatorTimeoutMs);
|
|
87
117
|
return {
|
|
88
|
-
entries:
|
|
118
|
+
entries: normalizeIndicatorResult(key, result),
|
|
89
119
|
indicatorKey: key
|
|
90
120
|
};
|
|
91
121
|
} catch (error) {
|
|
92
122
|
if (error instanceof HealthCheckError) {
|
|
93
123
|
return {
|
|
94
|
-
entries:
|
|
124
|
+
entries: normalizeIndicatorResult(key, error.causes),
|
|
95
125
|
indicatorKey: key
|
|
96
126
|
};
|
|
97
127
|
}
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,iBAAiB,CAAC;AAKzB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,iBAAiB,CAAC;AAKzB,OAAO,KAAK,EAA4D,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAuRlH,uFAAuF;AACvF,qBAAa,cAAc;IACzB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,qBAA0B,GAAG,UAAU;CAGhE"}
|
package/dist/module.js
CHANGED
|
@@ -62,6 +62,85 @@ function createTerminusProviders(options = {}) {
|
|
|
62
62
|
}
|
|
63
63
|
}];
|
|
64
64
|
}
|
|
65
|
+
function createPlatformHealthDiagnostic(health) {
|
|
66
|
+
if (health.status === 'healthy') {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
checks: health.checks,
|
|
71
|
+
message: health.reason ?? `Platform health reported ${health.status}.`,
|
|
72
|
+
platformStatus: health.status,
|
|
73
|
+
status: 'down'
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function createPlatformReadinessDiagnostic(readiness) {
|
|
77
|
+
if (readiness.status === 'ready') {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
checks: readiness.checks,
|
|
82
|
+
critical: readiness.critical,
|
|
83
|
+
message: readiness.reason ?? `Platform readiness reported ${readiness.status}.`,
|
|
84
|
+
platformStatus: readiness.status,
|
|
85
|
+
status: 'down'
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function createPlatformDiagnosticCollisionKey(diagnosticKey, seenKeys) {
|
|
89
|
+
const baseKey = `${diagnosticKey}-duplicate-key-error`;
|
|
90
|
+
if (!seenKeys.has(baseKey)) {
|
|
91
|
+
return baseKey;
|
|
92
|
+
}
|
|
93
|
+
let suffix = 2;
|
|
94
|
+
let candidate = `${baseKey}-${String(suffix)}`;
|
|
95
|
+
while (seenKeys.has(candidate)) {
|
|
96
|
+
suffix += 1;
|
|
97
|
+
candidate = `${baseKey}-${String(suffix)}`;
|
|
98
|
+
}
|
|
99
|
+
return candidate;
|
|
100
|
+
}
|
|
101
|
+
function appendPlatformDiagnostic(entries, existingKeys, diagnosticKey, diagnostic) {
|
|
102
|
+
if (diagnostic === undefined) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!existingKeys.has(diagnosticKey) && !(diagnosticKey in entries)) {
|
|
106
|
+
entries[diagnosticKey] = diagnostic;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const collisionKey = createPlatformDiagnosticCollisionKey(diagnosticKey, new Set([...existingKeys, ...Object.keys(entries)]));
|
|
110
|
+
entries[collisionKey] = {
|
|
111
|
+
message: `Platform diagnostic key "${diagnosticKey}" collided with an existing health result key.`,
|
|
112
|
+
status: 'down'
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function withPlatformDiagnostics(report, health, readiness) {
|
|
116
|
+
const platformDiagnostics = {};
|
|
117
|
+
const healthDiagnostic = createPlatformHealthDiagnostic(health);
|
|
118
|
+
const readinessDiagnostic = createPlatformReadinessDiagnostic(readiness);
|
|
119
|
+
const existingKeys = new Set(Object.keys(report.details));
|
|
120
|
+
appendPlatformDiagnostic(platformDiagnostics, existingKeys, 'fluo-platform-health', healthDiagnostic);
|
|
121
|
+
appendPlatformDiagnostic(platformDiagnostics, existingKeys, 'fluo-platform-readiness', readinessDiagnostic);
|
|
122
|
+
const platformDiagnosticKeys = Object.keys(platformDiagnostics);
|
|
123
|
+
return {
|
|
124
|
+
...report,
|
|
125
|
+
contributors: {
|
|
126
|
+
down: [...report.contributors.down, ...platformDiagnosticKeys],
|
|
127
|
+
up: [...report.contributors.up]
|
|
128
|
+
},
|
|
129
|
+
details: {
|
|
130
|
+
...report.details,
|
|
131
|
+
...platformDiagnostics
|
|
132
|
+
},
|
|
133
|
+
error: {
|
|
134
|
+
...report.error,
|
|
135
|
+
...platformDiagnostics
|
|
136
|
+
},
|
|
137
|
+
platform: {
|
|
138
|
+
health,
|
|
139
|
+
readiness
|
|
140
|
+
},
|
|
141
|
+
status: report.status === 'ok' && platformDiagnosticKeys.length === 0 ? 'ok' : 'error'
|
|
142
|
+
};
|
|
143
|
+
}
|
|
65
144
|
function createTerminusRuntimeModule(options = {}) {
|
|
66
145
|
const readinessChecks = [...(options.readinessChecks ?? [])];
|
|
67
146
|
const healthModule = createHealthModule({
|
|
@@ -69,17 +148,10 @@ function createTerminusRuntimeModule(options = {}) {
|
|
|
69
148
|
const healthService = await ctx.container.resolve(TerminusHealthService);
|
|
70
149
|
const platformShell = await ctx.container.resolve(PLATFORM_SHELL);
|
|
71
150
|
const [report, readiness, health] = await Promise.all([healthService.check(), platformShell.ready(), platformShell.health()]);
|
|
72
|
-
const
|
|
151
|
+
const reportWithPlatform = withPlatformDiagnostics(report, health, readiness);
|
|
73
152
|
return {
|
|
74
|
-
body:
|
|
75
|
-
|
|
76
|
-
platform: {
|
|
77
|
-
health,
|
|
78
|
-
readiness
|
|
79
|
-
},
|
|
80
|
-
status
|
|
81
|
-
},
|
|
82
|
-
statusCode: status === 'ok' ? 200 : 503
|
|
153
|
+
body: reportWithPlatform,
|
|
154
|
+
statusCode: reportWithPlatform.status === 'ok' ? 200 : 503
|
|
83
155
|
};
|
|
84
156
|
},
|
|
85
157
|
path: options.path
|
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.3",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -40,15 +40,15 @@
|
|
|
40
40
|
"dist"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@fluojs/
|
|
44
|
-
"@fluojs/
|
|
45
|
-
"@fluojs/
|
|
46
|
-
"@fluojs/
|
|
43
|
+
"@fluojs/di": "^1.0.0-beta.4",
|
|
44
|
+
"@fluojs/http": "^1.0.0-beta.3",
|
|
45
|
+
"@fluojs/core": "^1.0.0-beta.2",
|
|
46
|
+
"@fluojs/runtime": "^1.0.0-beta.4"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@fluojs/
|
|
50
|
-
"@fluojs/
|
|
51
|
-
"@fluojs/
|
|
49
|
+
"@fluojs/drizzle": "^1.0.0-beta.2",
|
|
50
|
+
"@fluojs/prisma": "^1.0.0-beta.2",
|
|
51
|
+
"@fluojs/redis": "^1.0.0-beta.2"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"@fluojs/drizzle": {
|