Files
MailUI4Agents/plugins/pi-mail-bridge/lib/crash-notify.mjs

69 lines
2.5 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.

/**
* 崩溃/异常终止时通过 Gateway API 发送邮件通知用户。
*
* 设计约束:
* - 不依赖任何外部库(崩溃场景下库可能已损坏)
* - 只用 Node.js 内置 http/https
* - 所有错误静默——通知失败不能让进程挂得更久
* - 只在崩溃路径uncaughtException/unhandledRejection/exit(1))调用
*
* Gateway 环境变量(同插件主进程):
* - AGENTMAIL_GATEWAY_URL默认 http://127.0.0.1:8180
* - AGENTMAIL_AGENT_KEYagent 密钥,用于 API 认证)
* - AGENTMAIL_AGENT_NAME发送者名称如 pi/dsh/opencode
*
* 注意:如果 Gateway 本身不可达(崩溃根因是 Gateway 挂了),通知发不出去——
* 这是可接受的Gateway 挂了邮件也发不出去,用户应该监控 Gateway 的 systemd 状态。
*/
import http from 'node:http';
const GATEWAY_URL = process.env.AGENTMAIL_GATEWAY_URL || 'http://127.0.0.1:8180';
const AGENT_NAME = process.env.AGENTMAIL_AGENT_NAME || 'unknown-bridge';
const AGENT_KEY = process.env.AGENTMAIL_AGENT_KEY || '';
/**
* 向 Gateway 发送崩溃通知邮件。
* @param {string} reason 终止原因描述
* @param {Error} [err] 原始错误对象(可选)
*/
export function notifyCrash(reason, err) {
if (!AGENT_KEY) return; // 没有密钥,没法发
const body = JSON.stringify({
to: 'jianf@',
subject: `[${AGENT_NAME}] 桥进程异常终止`,
body: [
`**${AGENT_NAME}** 桥进程遇到未处理异常,已终止。`,
'',
`**原因**${reason}`,
err ? `**错误信息**${err.message || String(err)}` : '',
err?.stack ? `\n**堆栈**(首 500 字):\n\`\`\`\n${err.stack.slice(0, 500)}\n\`\`\`` : '',
'',
`**自动重启**systemd 将在 5~10 秒内自动拉起。`,
`如果反复崩溃,请检查日志:`,
`- \`journalctl -u ${AGENT_NAME}-bridge -n 50 --no-pager\``,
`- \`journalctl -u ${AGENT_NAME} -n 50 --no-pager\``,
].filter(Boolean).join('\n'),
});
const parsed = new URL(`${GATEWAY_URL}/api/v1/agent/send`);
const req = http.request({
hostname: parsed.hostname,
port: parsed.port || 80,
path: parsed.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': AGENT_KEY,
'Content-Length': Buffer.byteLength(body),
},
timeout: 5000, // 5 秒超时
}, () => {});
req.on('error', () => {}); // 静默
req.on('timeout', () => { req.destroy(); });
req.write(body);
req.end();
}