Node.js比特币价格告警应用故障排查:未触发邮件发送求助
比特币价格告警邮件未发送问题排查与修复
以下是针对你代码中可能导致邮件未发送的问题分析及修复方案:
1. 异步邮件发送未正确等待
sendEmail 大概率是异步函数(比如调用邮件API通常返回Promise),但你在队列处理器中直接调用却没有用await,导致代码会在邮件发送完成前就执行done(),同时response会是一个Promise对象,而非包含error属性的结果,错误判断逻辑完全失效。
修复代码:
alertQueue.process(async function(job, done) { const {mailTo, title, text} = job.data; const mailObj = { from: process.env.SendGridForm, recipients: mailTo, subject: title, message: text } try { await sendEmail(mailObj); done(); } catch (err) { done(new Error(`Error Sending Alert: ${err.message}`)); } })
2. Alert保存操作未处理异步
在forEach循环中调用alert.save()但没有用await,这会导致:
- 数据库保存操作可能还未完成,下一次Cron任务运行时,该Alert的状态还是
Created,会重复触发告警 - 保存失败的错误无法被捕获,无法排查问题
修复方案:把forEach换成for...of循环,支持异步等待:
// 替换原有的alerts.forEach(...) for (const alert of alerts) { if(alert.price <= price) { const mailTo = alert.email; const title = `Bitcoin is UP!`; const text = `Price of Bitcoin has just exceeded your alert price of ${alert.price} USD. Current price is ${price} USD.`; await alertQueue.add( {mailTo, title, text}, { attempts: 3, backoff: 3000 } ) alert.status = "Triggered"; await alert.save(); } }
3. 未声明变量导致的潜在问题
mailTo、title、text在循环中直接赋值,没有用let/const声明,会成为全局变量,在并发处理多个Alert时可能出现变量值被覆盖的情况。
修复:如上一段代码所示,给这些变量添加const声明。
4. 缺少队列错误监听
Bull队列如果连接Redis失败或者出现其他内部错误,不会主动抛出到控制台,导致你无法察觉队列是否正常运行。
添加错误监听:
// 创建队列后添加以下代码 alertQueue.on('error', (err) => { console.error('Alert Queue Error:', err); }); alertQueue.on('failed', (job, err) => { console.error(`Job ${job.id} failed:`, err.message); });
5. 日志缺失导致无法定位问题
没有添加关键步骤的日志,无法确认:
- Cron任务是否按时触发
- 是否正确获取到比特币价格
- 是否找到符合条件的Alert
- 队列是否成功添加任务
添加日志示例:
let sendAlert = new CronJob("*/25 * * * * *", async function () { console.log('Cron job triggered at:', new Date()); let priceObj = await currentPrice(); if (priceObj.error) { console.error('Failed to get Bitcoin price:', priceObj.error); return; } let price = priceObj.data; console.log('Current Bitcoin price:', price); const alerts = await Alert.find({status: "Created"}); console.log(`Found ${alerts.length} active alerts`); for (const alert of alerts) { if(alert.price <= price) { console.log(`Triggering alert for ${alert.email} (threshold: ${alert.price})`); // ... 后续代码 } } });
额外检查点
- 确认
.env文件中的RedisURL、SendGridForm等配置项是否正确 - 验证
sendEmail函数本身是否正常工作,可以单独写测试代码调用该函数发送邮件 - 检查Redis服务是否正常运行,队列是否能正常连接Redis
内容的提问来源于stack exchange,提问作者Sachin
相关产品推荐
相关产品推荐

