zhizhi/backend/coldstart/server.js

141 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require("express");
const fs = require("fs");
const path = require("path");
const axios = require("axios");
const moment = require("moment");
const app = express();
app.use(express.json());
// 读取配置文件
const config = require("./config.json");
const PORT = config.serverPort || 3014;
const WEBHOOK_URL = config.webhookUrl;
const LOG_PATH = path.join(__dirname, config.logPath);
const RETRY_COUNT = config.retryCount || 3;
// 确保日志目录存在
if (!fs.existsSync(LOG_PATH)) {
fs.mkdirSync(LOG_PATH, { recursive: true });
}
// 日志写入函数
const writeLog = (content) => {
const logFile = path.join(LOG_PATH, `warmup-${moment().format("YYYY-MM-DD")}.log`);
const logContent = `[${moment().toISOString()}] ${content}\\n`;
fs.appendFileSync(logFile, logContent, "utf8");
};
// 飞书Webhook通知函数
const sendFeishuWebhook = async (warmupData) => {
if (!WEBHOOK_URL) {
writeLog("Webhook通知失败未配置webhookUrl");
return { success: false, reason: "未配置webhookUrl" };
}
try {
const notifyData = {
msg_type: "text",
content: {
text: `冷启动热身通知:\n状态:${warmupData.status}\n耗时:${warmupData.elapsed}ms\n时间:${moment(warmupData.timestamp).toISOString()}`
}
};
await axios.post(WEBHOOK_URL, notifyData, { timeout: 5000 });
writeLog(`Webhook通知成功${JSON.stringify(warmupData)}`);
return { success: true };
} catch (error) {
const errMsg = `Webhook通知失败${error.message}`;
writeLog(errMsg);
return { success: false, reason: errMsg };
}
};
// 热身核心函数
const warmup = async () => {
const startTime = Date.now();
let status = "success";
let details = "热身执行成功";
try {
// 模拟热身业务逻辑
await new Promise(resolve => setTimeout(resolve, 10));
} catch (error) {
status = "fail";
details = `热身执行失败:${error.message}`;
writeLog(details);
}
const elapsed = Date.now() - startTime;
const warmupData = {
timestamp: new Date().toISOString(),
status,
elapsed,
details
};
// 发送Webhook通知不阻塞热身流程
sendFeishuWebhook(warmupData);
writeLog(`热身完成:${JSON.stringify(warmupData)}`);
return warmupData;
};
// 自动热身(带失败重试)
const autoWarmup = async (retry = 0) => {
writeLog(`开始自动热身(第${retry + 1}次)`);
const result = await warmup();
if (result.status === "fail" && retry < RETRY_COUNT - 1) {
writeLog(`自动热身失败,将进行第${retry + 2}次重试`);
setTimeout(() => autoWarmup(retry + 1), 1000);
} else if (result.status === "fail") {
writeLog("自动热身重试次数用尽,执行失败");
}
};
// 接口:手动触发热身
app.get("/warmup", async (req, res) => {
try {
const result = await warmup();
res.json({ code: 200, msg: "success", data: result });
} catch (error) {
res.json({ code: 500, msg: "fail", error: error.message });
}
});
// 接口:自动热身状态
app.get("/warmup/auto", (req, res) => {
res.json({
code: 200,
msg: "success",
data: {
autoWarmupEnabled: true,
retryCount: RETRY_COUNT,
lastRun: moment().subtract(5, "minutes").toISOString()
}
});
});
// 接口:查询日志
app.get("/warmup/logs", (req, res) => {
try {
const logFile = path.join(LOG_PATH, `warmup-${moment().format("YYYY-MM-DD")}.log`);
if (fs.existsSync(logFile)) {
const logs = fs.readFileSync(logFile, "utf8").split("\\n").filter(line => line);
res.json({ code: 200, msg: "success", data: logs });
} else {
res.json({ code: 200, msg: "success", data: ["暂无日志"] });
}
} catch (error) {
res.json({ code: 500, msg: "fail", error: error.message });
}
});
// 环节3新增触发Webhook通知接口
app.post("/warmup/notify", async (req, res) => {
try {
const warmupData = req.body;
if (!warmupData.status || !warmupData.elapsed) {
return res.json({ code: 400, msg: "fail", error: "缺少必传参数status/elapsed" });
}
const notifyResult = await sendFeishuWebhook(warmupData);
if (notifyResult.success) {
res.json({ code: 200, msg: "Webhook通知发送成功" });
} else {
res.json({ code: 500, msg: "Webhook通知发送失败", reason: notifyResult.reason });
}
} catch (error) {
res.json({ code: 500, msg: "fail", error: error.message });
}
});
// 启动服务+自动热身
app.listen(PORT, () => {
console.log(`冷启动热身服务启动成功,端口:${PORT}`);
writeLog(`服务启动成功,端口:${PORT}`);
autoWarmup(); // 启动时执行自动热身
});
module.exports = app;