chore: normalize test-server health governance
This commit is contained in:
@@ -1 +1 @@
|
|||||||
0.5.4
|
0.5.5
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# CloudSearch 测试服治理说明
|
||||||
|
|
||||||
|
## 当前测试服定位
|
||||||
|
|
||||||
|
`/root/cloudsearch_deploy` 是当前 Docker Compose 实际运行目录。`CloudSearch_App` 的 compose label 与挂载均指向该目录。
|
||||||
|
|
||||||
|
## 健康检查口径
|
||||||
|
|
||||||
|
`Video Parser` 当前仍是待开发/未部署能力。测试服健康判断应区分核心必需组件与可选/开发中能力。
|
||||||
|
|
||||||
|
源码中的 `computeOverallHealth()` 支持通过 `VIDEO_PARSER_REQUIRED=true` 将 Video Parser 纳入必需健康判定;未设置时按可选能力处理。
|
||||||
|
|
||||||
|
## 版本来源
|
||||||
|
|
||||||
|
根目录 `VERSION` 与 `source_clean/VERSION` 当前均为 `0.5.5`。构建脚本会从根目录 `VERSION` 复制到 `source_clean/VERSION` 再构建镜像。
|
||||||
|
|
||||||
|
## 验证命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /root/cloudsearch_deploy/source_clean
|
||||||
|
npm run build
|
||||||
|
npm test -- --run src/health/health.test.ts
|
||||||
|
curl -fsS http://127.0.0.1:9527/health
|
||||||
|
```
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { computeOverallHealth } from './health';
|
||||||
|
|
||||||
|
describe('computeOverallHealth', () => {
|
||||||
|
it('returns ok when core services are healthy and the video parser is optional', () => {
|
||||||
|
const status = computeOverallHealth({
|
||||||
|
dbOk: true,
|
||||||
|
redisStatus: 'connected',
|
||||||
|
pansouStatus: 'ok',
|
||||||
|
videoParserStatus: 'unreachable',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe('ok');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns degraded when the video parser is required but unavailable', () => {
|
||||||
|
const status = computeOverallHealth(
|
||||||
|
{
|
||||||
|
dbOk: true,
|
||||||
|
redisStatus: 'connected',
|
||||||
|
pansouStatus: 'ok',
|
||||||
|
videoParserStatus: 'unreachable',
|
||||||
|
},
|
||||||
|
{ videoParserRequired: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(status).toBe('degraded');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
export type HealthStatus = 'ok' | 'degraded' | 'unhealthy';
|
||||||
|
|
||||||
|
export interface HealthInputs {
|
||||||
|
dbOk: boolean;
|
||||||
|
redisStatus: string;
|
||||||
|
pansouStatus: string;
|
||||||
|
videoParserStatus: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HealthOptions {
|
||||||
|
videoParserRequired?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computeOverallHealth(
|
||||||
|
{ dbOk, redisStatus, pansouStatus, videoParserStatus }: HealthInputs,
|
||||||
|
options: HealthOptions = {},
|
||||||
|
): HealthStatus {
|
||||||
|
const videoParserRequired = options.videoParserRequired ?? false;
|
||||||
|
|
||||||
|
if (dbOk && redisStatus === 'connected' && pansouStatus === 'ok') {
|
||||||
|
if (!videoParserRequired || videoParserStatus === 'ok') {
|
||||||
|
return 'ok';
|
||||||
|
}
|
||||||
|
return 'degraded';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbOk && redisStatus !== 'unknown' && pansouStatus !== 'unreachable') {
|
||||||
|
return 'degraded';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'unhealthy';
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import morgan from 'morgan';
|
|||||||
import config from './config';
|
import config from './config';
|
||||||
import { VERSION as version } from "./version";
|
import { VERSION as version } from "./version";
|
||||||
import { checkStartup } from './config/startup-validator';
|
import { checkStartup } from './config/startup-validator';
|
||||||
|
import { computeOverallHealth } from './health/health';
|
||||||
import { getDb } from './database/database';
|
import { getDb } from './database/database';
|
||||||
import { connectRedis, disconnectRedis, reconnectRedis, testRedisConnection } from './middleware/cache';
|
import { connectRedis, disconnectRedis, reconnectRedis, testRedisConnection } from './middleware/cache';
|
||||||
import rateLimiter from './middleware/rate-limit';
|
import rateLimiter from './middleware/rate-limit';
|
||||||
@@ -104,11 +105,15 @@ app.get('/health', async (_req, res) => {
|
|||||||
} catch { return 'unreachable'; }
|
} catch { return 'unreachable'; }
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const overall = dbOk && redisStatus === 'connected' && pansouStatus === 'ok' && videoParserStatus === 'ok'
|
const overall = computeOverallHealth(
|
||||||
? 'ok'
|
{
|
||||||
: dbOk && redisStatus !== 'unknown' && pansouStatus !== 'unreachable'
|
dbOk,
|
||||||
? 'degraded'
|
redisStatus,
|
||||||
: 'unhealthy';
|
pansouStatus,
|
||||||
|
videoParserStatus,
|
||||||
|
},
|
||||||
|
{ videoParserRequired: process.env.VIDEO_PARSER_REQUIRED === 'true' },
|
||||||
|
);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
version,
|
version,
|
||||||
|
|||||||
Reference in New Issue
Block a user