feat(web): T-WEB-001 NestJS 骨架 + 连接现有 MySQL 实例
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { Controller, Get, Res, ServiceUnavailableException } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { Response } from 'express';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { AppConfig } from '../config/configuration';
|
||||
import { detectAssimp } from '../preprocess/assimp';
|
||||
|
||||
export interface HealthReport {
|
||||
status: 'ok' | 'degraded';
|
||||
uptimeSec: number;
|
||||
version: string;
|
||||
contractVersion: Record<string, string>;
|
||||
database: {
|
||||
connected: boolean;
|
||||
server: string | null;
|
||||
database: string | null;
|
||||
migrationsPending: number | null;
|
||||
error?: string;
|
||||
};
|
||||
storage: {
|
||||
dir: string;
|
||||
files: number;
|
||||
totalBytes: number;
|
||||
};
|
||||
assimp: {
|
||||
available: boolean;
|
||||
version?: string;
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
@Controller('health')
|
||||
export class HealthController {
|
||||
constructor(
|
||||
@InjectDataSource() private readonly dataSource: DataSource,
|
||||
private readonly config: AppConfig,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 健康检查:必须真实探测数据库连通性(T-WEB-010 验收要求
|
||||
* `curl http://localhost:3000/health` 通过)。
|
||||
*/
|
||||
@Get()
|
||||
async check(@Res({ passthrough: true }) res: Response): Promise<HealthReport> {
|
||||
const database: HealthReport['database'] = {
|
||||
connected: false,
|
||||
server: null,
|
||||
database: null,
|
||||
migrationsPending: null,
|
||||
};
|
||||
|
||||
try {
|
||||
const rows = await this.dataSource.query<Array<{ version: string; db: string }>>(
|
||||
'SELECT VERSION() AS version, DATABASE() AS db',
|
||||
);
|
||||
database.connected = true;
|
||||
database.server = rows[0]?.version ?? null;
|
||||
database.database = rows[0]?.db ?? null;
|
||||
const pending = await this.dataSource.showMigrations();
|
||||
database.migrationsPending = pending ? 1 : 0;
|
||||
} catch (error) {
|
||||
database.error = error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
const assimp = await detectAssimp(this.config.assimpBin);
|
||||
|
||||
const report: HealthReport = {
|
||||
status: database.connected ? 'ok' : 'degraded',
|
||||
uptimeSec: Math.round(process.uptime() * 1000) / 1000,
|
||||
version: process.env.npm_package_version ?? '0.1.0',
|
||||
contractVersion: this.config.contractVersions,
|
||||
database,
|
||||
storage: {
|
||||
dir: this.config.storageDir,
|
||||
files: 0,
|
||||
totalBytes: 0,
|
||||
},
|
||||
assimp,
|
||||
};
|
||||
|
||||
if (!database.connected) {
|
||||
res.status(503);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HealthController } from './health.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [HealthController],
|
||||
})
|
||||
export class HealthModule {}
|
||||
Reference in New Issue
Block a user