fix(system-monitor): 改进进程CPU使用率计算准确性和稳定性

- 优先使用Node.js内置的process.cpuUsage()计算当前进程CPU使用率,提高跨平台准确性
- 为外部进程ps命令添加错误处理,避免在BusyBox环境下报错干扰日志
- 更新Dockerfile安装procps工具以支持系统监控功能
- 同步更新版本号至2.11.1
This commit is contained in:
hex2077 2026-03-09 19:05:41 +08:00
parent f2f02b365f
commit 7d2704b14e
3 changed files with 40 additions and 11 deletions

View file

@ -19,8 +19,8 @@ FROM node:20-alpine
LABEL maintainer="AIClient2API Team"
LABEL description="Docker image for AIClient2API server"
# 安装必要的系统工具tar 用于更新功能git 用于版本检查
RUN apk add --no-cache tar git
# 安装必要的系统工具tar 用于更新功能git 用于版本检查procps 用于系统监控
RUN apk add --no-cache tar git procps
# 设置工作目录
WORKDIR /app

View file

@ -1 +1 @@
2.11.0
2.11.1

View file

@ -57,8 +57,31 @@ export function getProcessCpuUsagePercent(pid) {
const isWindows = process.platform === 'win32';
let cpuPercent = 0;
if (isWindows) {
// Windows 下使用 PowerShell 获取进程的 CPU 使用率
// 优先处理当前进程,使用 Node.js 内置的 process.cpuUsage(),这在所有平台上都更准确且无需外部命令
if (pid === process.pid) {
const usage = process.cpuUsage();
const timestamp = Date.now();
const totalMicroseconds = usage.user + usage.system;
const prevInfo = processCpuInfoMap.get(pid);
if (prevInfo && prevInfo.totalMicroseconds !== undefined) {
const timeDiff = (timestamp - prevInfo.timestamp) * 1000; // 转换为微秒
const processTimeDiff = totalMicroseconds - prevInfo.totalMicroseconds;
if (timeDiff > 0) {
const cpuCount = os.cpus().length;
cpuPercent = (processTimeDiff / timeDiff) * 100;
// Node.js 返回的是所有核心累加的使用量,归一化到 0-100%
cpuPercent = cpuPercent / cpuCount;
}
}
processCpuInfoMap.set(pid, {
totalMicroseconds,
timestamp
});
} else if (isWindows) {
// Windows 下使用 PowerShell 获取其他进程的 CPU 使用率
// CPU = (Process.TotalProcessorTime / ElapsedTime) / ProcessorCount
const command = `powershell -Command "Get-Process -Id ${pid} | Select-Object -ExpandProperty TotalProcessorTime | ForEach-Object { $_.TotalSeconds }"`;
const output = execSync(command, { encoding: 'utf8' }).trim();
@ -67,7 +90,7 @@ export function getProcessCpuUsagePercent(pid) {
if (!isNaN(totalProcessorSeconds)) {
const prevInfo = processCpuInfoMap.get(pid);
if (prevInfo) {
if (prevInfo && prevInfo.totalProcessorSeconds !== undefined) {
const timeDiff = (timestamp - prevInfo.timestamp) / 1000; // 转换为秒
const processTimeDiff = totalProcessorSeconds - prevInfo.totalProcessorSeconds;
@ -85,11 +108,17 @@ export function getProcessCpuUsagePercent(pid) {
});
}
} else {
// Linux/macOS 使用 ps 命令直接获取
const output = execSync(`ps -p ${pid} -o %cpu`, { encoding: 'utf8' });
const lines = output.trim().split('\n');
if (lines.length >= 2) {
cpuPercent = parseFloat(lines[1].trim());
// Linux/macOS 使用 ps 命令获取其他进程的 CPU 使用率
// 增加 2> /dev/null 以防在 BusyBox 等环境下报错干扰日志
try {
const output = execSync(`ps -p ${pid} -o %cpu 2>/dev/null`, { encoding: 'utf8' });
const lines = output.trim().split('\n');
if (lines.length >= 2) {
cpuPercent = parseFloat(lines[1].trim());
}
} catch (e) {
// 如果 ps -p 失败,尝试更通用的 ps 方式或直接忽略
cpuPercent = 0;
}
}