Node.js回调后是否继续执行语句?Lambda+MySQL场景技术咨询
在Lambda的Node.js函数中实现「存MySQL→执行回调→发推送」的异步流程
看起来你想在MySQL数据保存完成后先跑一个回调操作,再触发推送通知,同时还要保证Lambda能正确处理这些异步步骤对吧?我给你整理两种可行的方案,代码清晰还能满足你的需求:
方案一:用传统回调嵌套(适合习惯回调写法的场景)
这种方式通过嵌套回调确保执行顺序,同时注意Lambda的特殊配置:
const AWS = require('aws-sdk'); var mysql = require('mysql'); var apn = require("apn"); exports.handler = (event, context, callback) => { // 关键设置:不让Lambda等待事件循环为空,避免不必要的超时 context.callbackWaitsForEmptyEventLoop = false; // 创建数据库连接 var connection = mysql.createConnection({ host: '你的数据库地址', user: '数据库用户名', password: '数据库密码', database: '目标数据库名' }); // 第一步:连接数据库并保存数据 connection.connect((connErr) => { if (connErr) { console.error('数据库连不上:', connErr); callback(connErr); return; } console.log('数据库连接成功'); // 执行数据插入 const saveSql = 'INSERT INTO 你的表名 (字段1, 字段2) VALUES (?, ?)'; const saveValues = ['测试值1', '测试值2']; connection.query(saveSql, saveValues, (saveErr, saveResult) => { if (saveErr) { console.error('数据存失败了:', saveErr); connection.end(); // 出错也要关连接 callback(saveErr); return; } console.log(`数据保存完成,影响了${saveResult.affectedRows}行`); // 第二步:执行你要加的回调操作 function afterSaveCallback(callbackDone) { console.log('开始执行保存后的回调任务'); // 这里替换成你的实际回调逻辑,比如写日志、更新缓存、调用其他API setTimeout(() => { console.log('回调任务搞定啦'); callbackDone(null); // 告诉主流程可以继续往下走 }, 1000); // 模拟异步任务耗时 } // 回调完成后再执行推送 afterSaveCallback((callbackErr) => { if (callbackErr) { console.error('回调任务翻车了:', callbackErr); connection.end(); callback(callbackErr); return; } // 第三步:发送APN推送 const apnProvider = new apn.Provider({ token: { key: '你的APN密钥文件路径', keyId: '密钥ID', teamId: '苹果开发者团队ID' }, production: false // 测试环境设为false,生产设为true }); const pushNote = new apn.Notification(); pushNote.expiry = Math.floor(Date.now() / 1000) + 3600; // 1小时后过期 pushNote.badge = 1; pushNote.sound = "ping.aiff"; pushNote.alert = "你的数据已经保存成功啦!"; pushNote.payload = {'source': 'AWS Lambda'}; pushNote.topic = '你的App Bundle ID'; // 发送推送 apnProvider.send(pushNote, '目标设备Token').then((pushResult) => { console.log('推送发送结果:', pushResult); // 清理资源 apnProvider.shutdown(); connection.end(); callback(null, {status: 'success', msg: '所有流程都走完啦'}); }).catch((pushErr) => { console.error('推送发失败了:', pushErr); apnProvider.shutdown(); connection.end(); callback(pushErr); }); }); }); }); };
这个方案的关键注意点:
- 一定要设置
context.callbackWaitsForEmptyEventLoop = false,不然Lambda会一直等事件循环为空,可能导致超时。 - 不管哪个步骤出错,都要关闭数据库连接和APN Provider,避免资源泄漏。
- 回调函数里必须调用
callbackDone来通知主流程继续,不然推送代码永远不会执行。
方案二:用Async/Await(更清晰,推荐)
如果你的Node.js版本支持(Lambda现在默认支持),用async-await可以避免回调地狱,代码可读性更强:
const AWS = require('aws-sdk'); var mysql = require('mysql2/promise'); // 用mysql2的Promise版本,支持async-await var apn = require("apn"); exports.handler = async (event, context) => { context.callbackWaitsForEmptyEventLoop = false; let connection; let apnProvider; try { // 1. 连接数据库 connection = await mysql.createConnection({ host: '你的数据库地址', user: '数据库用户名', password: '数据库密码', database: '目标数据库名' }); console.log('数据库连接成功'); // 2. 保存数据到MySQL const saveSql = 'INSERT INTO 你的表名 (字段1, 字段2) VALUES (?, ?)'; const saveValues = ['测试值1', '测试值2']; const [saveResult] = await connection.execute(saveSql, saveValues); console.log(`数据保存完成,影响了${saveResult.affectedRows}行`); // 3. 执行保存后的回调操作 const runAfterSaveCallback = async () => { console.log('开始执行回调任务'); // 替换成你的实际回调逻辑,比如调用其他服务、更新缓存 await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟异步任务 console.log('回调任务完成'); }; await runAfterSaveCallback(); // 4. 发送APN推送 apnProvider = new apn.Provider({ token: { key: '你的APN密钥文件路径', keyId: '密钥ID', teamId: '苹果开发者团队ID' }, production: false }); const pushNote = new apn.Notification(); pushNote.expiry = Math.floor(Date.now() / 1000) + 3600; pushNote.badge = 1; pushNote.sound = "ping.aiff"; pushNote.alert = "你的数据已经保存成功啦!"; pushNote.payload = {'source': 'AWS Lambda'}; pushNote.topic = '你的App Bundle ID'; const pushResult = await apnProvider.send(pushNote, '目标设备Token'); console.log('推送发送结果:', pushResult); // 清理资源 await connection.end(); apnProvider.shutdown(); return {status: 'success', msg: '所有操作都完成了'}; } catch (err) { console.error('流程出错了:', err); // 出错时也要清理资源 if (connection) await connection.end(); if (apnProvider) apnProvider.shutdown(); throw err; // 抛出错误让Lambda捕获并返回失败结果 } };
这个方案的优势:
- 代码线性化,逻辑一目了然,不用层层嵌套。
- 用try-catch统一处理所有错误,不用每个异步操作单独写错误处理。
- 用
mysql2/promise比原生mysql更适合异步场景。
额外提醒
- Lambda超时设置:如果你的回调和推送操作比较耗时,记得在Lambda控制台把超时时间调长(最大支持15分钟),避免中途被终止。
- 数据库连接:Lambda里不要保持长连接,每次调用新建连接、用完就关,不然会导致连接池耗尽。
- APN密钥:确保你的APN密钥文件已经上传到Lambda的层或者代码包中,路径要正确。
内容的提问来源于stack exchange,提问作者alionthego
相关产品推荐
相关产品推荐

