// ===== 已停用 ===== // 服务自检的定时任务已从 server/cron.js 移除 (服务监控暂留空)。 // 如恢复服务监控, 重新在 cron.js 注册 runOnce 并复用本文件。 // 服务健康检查: 探测本应用各关键端点, 写入 ServiceCheck 表 const mysql = require('mysql2/promise') function parseUrl(url) { const u = new URL(url); return { host: u.hostname, port: Number(u.port) || 3306, user: decodeURIComponent(u.username), password: decodeURIComponent(u.password), database: u.pathname.replace(/^\//, '') } } const TARGETS = [ { name: 'api-health', url: 'http://127.0.0.1:' + (process.env.PORT || 3001) + '/api/health' }, { name: 'auth-login', url: 'http://127.0.0.1:' + (process.env.PORT || 3001) + '/api/auth/login' }, ] async function probeOne(target) { const t0 = Date.now() try { const ctrl = new AbortController() setTimeout(() => ctrl.abort(), 8000) const r = await fetch(target.url, { method: 'GET', signal: ctrl.signal }) const latency = Date.now() - t0 const status = (r.ok || r.status === 400 || r.status === 401) ? 'up' : 'down' const msg = 'HTTP ' + r.status return { name: target.name, url: target.url, status, latencyMs: latency, message: msg } } catch (e) { return { name: target.name, url: target.url, status: 'down', latencyMs: Date.now() - t0, message: e.message || String(e) } } } async function checkDb() { const t0 = Date.now() try { const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL)) await conn.execute('SELECT 1') await conn.end() return { name: 'database', url: 'mysql://' + (new URL(process.env.DATABASE_URL)).host, status: 'up', latencyMs: Date.now() - t0, message: 'ok' } } catch (e) { return { name: 'database', url: 'mysql', status: 'down', latencyMs: Date.now() - t0, message: e.message } } } async function runOnce() { const results = await Promise.all([...TARGETS.map(probeOne), checkDb()]) const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL)) try { for (const r of results) { await conn.execute( 'INSERT INTO `ServiceCheck` (`name`,`url`,`status`,`latencyMs`,`message`,`lastCheckAt`,`createdAt`,`updatedAt`) VALUES (?,?,?,?,?,NOW(3),NOW(3),NOW(3)) ' + 'ON DUPLICATE KEY UPDATE `url`=VALUES(`url`),`status`=VALUES(`status`),`latencyMs`=VALUES(`latencyMs`),`message`=VALUES(`message`),`lastCheckAt`=NOW(3),`updatedAt`=NOW(3)', [r.name, r.url, r.status, r.latencyMs, r.message.slice(0, 180)], ) } } finally { await conn.end() } return results } module.exports = { runOnce, TARGETS }