PM2运行Webhook脚本时exec回调内sendEmail无法触发求助
问题分析与修复方案
核心原因
你遇到的问题本质是:PM2运行webhook脚本时,deploy-script.sh里的PM2重启操作会直接终止当前webhook进程——因为脚本里重启了PM2管理的所有服务(包括这个webhook进程本身),导致exec的回调函数还没来得及执行,进程就被杀死了。而手动运行时,进程不受PM2管控,重启PM2不会影响当前终端里的进程,所以回调能正常跑完。
修复方案
方案1:把邮件逻辑移出webhook进程
直接把发送部署结果邮件的步骤加到deploy-script.sh末尾,让它独立于webhook进程执行:
- 修改
deploy-script.sh,在所有部署、重启操作完成后,调用单独的发邮件脚本:
这种方式不管webhook进程是否被重启,邮件发送逻辑都能独立执行。# 在deploy-script.sh最后添加 node /home/app_template_operator/app_template/server/scripts/send-deploy-email.js "部署完成通知" "$(cat ./deploy-log.txt)"
方案2:让webhook进程避开PM2重启范围
调整PM2配置,把webhook服务单独分组,这样重启其他服务时不会波及它:
- 修改PM2配置文件(比如
ecosystem.config.js):module.exports = { apps: [ // 应用主服务、静态服务归为一组 { name: 'app-main', script: 'server/main.js', // 其他配置... }, { name: 'app-static', script: 'server/static.js', // 其他配置... }, // Webhook服务单独设置,不参与通用重启 { name: 'webhook-service', script: 'server/scripts/webhook_3002.js', exec_mode: 'fork', watch: false, namespace: 'webhook-only' } ] }; - 然后修改
deploy-script.sh里的PM2重启命令,只重启主服务和静态服务:pm2 restart app-main app-static
方案3:让exec子进程脱离当前进程控制
如果必须在webhook进程内发邮件,可以改用child_process.execFile,让deploy脚本在独立子进程中运行,即使当前webhook进程被杀死,子进程的回调也能完成:
- 修改webhook脚本中调用exec的代码:
const { execFile } = require('child_process'); const deployPath = '/home/app_template_operator/app_template/deploy-script.sh'; // 用execFile替代exec,设置detached让子进程独立 execFile(deployPath, [], { detached: true, stdio: 'ignore' }, (error, stdout, stderr) => { if (error) { console.error(`部署失败: ${error.message}`); sendEmail('部署失败', stderr || error.message); } else { console.log(`部署成功: ${stdout}`); sendEmail('部署成功', stdout); } }).unref(); // 让子进程脱离当前进程控制,不受进程终止影响
验证步骤
- 选一种方案修改后,用
pm2 restart ecosystem.config.js重启所有服务 - 触发GitHub Webhook,等待部署完成
- 检查是否收到邮件,同时用
pm2 logs webhook-service查看webhook进程日志确认回调执行情况
内容的提问来源于stack exchange,提问作者Samuel Amann
相关产品推荐
相关产品推荐

