From d79c11fb158e9f50728f9e948c3970c509515a3a Mon Sep 17 00:00:00 2001 From: admin <362324317@qq.com> Date: Thu, 21 May 2026 14:21:27 +0800 Subject: [PATCH] chore: normalize test-server health governance --- source_clean/VERSION | 2 +- source_clean/docs/test-server-governance.md | 24 ++++++++++++++++ source_clean/src/health/health.test.ts | 29 +++++++++++++++++++ source_clean/src/health/health.ts | 32 +++++++++++++++++++++ source_clean/src/main.ts | 15 ++++++---- 5 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 source_clean/docs/test-server-governance.md create mode 100644 source_clean/src/health/health.test.ts create mode 100644 source_clean/src/health/health.ts diff --git a/source_clean/VERSION b/source_clean/VERSION index 7d85683..d1d899f 100644 --- a/source_clean/VERSION +++ b/source_clean/VERSION @@ -1 +1 @@ -0.5.4 +0.5.5 diff --git a/source_clean/docs/test-server-governance.md b/source_clean/docs/test-server-governance.md new file mode 100644 index 0000000..1fa561d --- /dev/null +++ b/source_clean/docs/test-server-governance.md @@ -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 +``` diff --git a/source_clean/src/health/health.test.ts b/source_clean/src/health/health.test.ts new file mode 100644 index 0000000..dc9a22d --- /dev/null +++ b/source_clean/src/health/health.test.ts @@ -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'); + }); +}); diff --git a/source_clean/src/health/health.ts b/source_clean/src/health/health.ts new file mode 100644 index 0000000..f81daa2 --- /dev/null +++ b/source_clean/src/health/health.ts @@ -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'; +} diff --git a/source_clean/src/main.ts b/source_clean/src/main.ts index c97f7b6..9ab05a5 100755 --- a/source_clean/src/main.ts +++ b/source_clean/src/main.ts @@ -6,6 +6,7 @@ import morgan from 'morgan'; import config from './config'; import { VERSION as version } from "./version"; import { checkStartup } from './config/startup-validator'; +import { computeOverallHealth } from './health/health'; import { getDb } from './database/database'; import { connectRedis, disconnectRedis, reconnectRedis, testRedisConnection } from './middleware/cache'; import rateLimiter from './middleware/rate-limit'; @@ -104,11 +105,15 @@ app.get('/health', async (_req, res) => { } catch { return 'unreachable'; } })(); - const overall = dbOk && redisStatus === 'connected' && pansouStatus === 'ok' && videoParserStatus === 'ok' - ? 'ok' - : dbOk && redisStatus !== 'unknown' && pansouStatus !== 'unreachable' - ? 'degraded' - : 'unhealthy'; + const overall = computeOverallHealth( + { + dbOk, + redisStatus, + pansouStatus, + videoParserStatus, + }, + { videoParserRequired: process.env.VIDEO_PARSER_REQUIRED === 'true' }, + ); res.json({ version,