iboard/server/health-check.cjs
2026-08-06 16:41:47 +08:00

56 lines
2.4 KiB
JavaScript

// 服务健康检查: 探测本应用各关键端点, 写入 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 }