AWS API Gateway随机502错误伴Lambda运行时段错误排查求助
问题排查:AWS Lambda + API Gateway 随机502错误
问题现象
- 通过API Gateway调用Node.js Lambda函数,频繁随机返回502错误,立即重试相同请求可获得正常响应
- 日志记录两类错误:
Runtime exited with error: signal: segmentation fault Runtime.ExitError- 带有
PROTOCOL_SEQUENCE_TIMEOUT代码的Quit inactivity timeout未捕获异常,具体日志:
xxxx ERROR Uncaught Exception { "errorType": "Error", "errorMessage": "Quit inactivity timeout", "code": "PROTOCOL_SEQUENCE_TIMEOUT", "fatal": true, "timeout": 30000, "stack": [ "Error: Quit inactivity timeout", " at Quit.<anonymous> (/opt/nodejs/node_modules/mysql/lib/protocol/Protocol.js:160:17)", " at Quit.emit (node:events:527:28)", " at Quit.emit (node:domain:475:12)", " at Quit._onTimeout (/opt/nodejs/node_modules/mysql/lib/protocol/sequences/Sequence.js:124:8)", " at Timer._onTimeout (/opt/nodejs/node_modules/mysql/lib/protocol/Timer.js:32:23)", " at listOnTimeout (node:internal/timers:559:17)", " at processTimers (node:internal/timers:502:7)" ] }
相关代码
MySQL连接器代码
const CustomSecret = require('../secrets/CustomSecret'); const mysql = require("mysql"); module.exports = class MySqlConnect { databaseCredObject; constructor() { } async queryDb(sql, args) { if (!this.databaseCredObject) { await this.fetchSecret(); } let connection = null; const connection_settings = { host: this.databaseCredObject.host, user: this.databaseCredObject.username, password: this.databaseCredObject.password, database: 'logbook' }; connection = mysql.createConnection(connection_settings); return new Promise((resolve, reject) => { connection.connect(function (err) { if (err) { console.log('error when connecting to db:', err); } else { console.log('Connected'); connection.query(sql, args, function (err, result) { connection.end(); if (err) { return reject(err); } return resolve(result); }); } }); }); } async fetchSecret() { const databaseCredString = await CustomSecret.getSecret('secretname', 'eu-west-2'); this.databaseCredObject = JSON.parse(databaseCredString); } }
Lambda函数代码
const {compress, decompress} = require("compress-json"); const MySqlConnect = require("customPackagePath/MySqlConnect"); const CustomJwt = require("customPackagePath/CustomJwt"); const AWS = require("aws-sdk"); const warmer = require("lambda-warmer"); exports.handler = async (event) => { if (await warmer(event)) { console.log("Warming"); return 'warmed'; } let responseCode = 200; let response = {}; response.headers = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }; const bodyContent = JSON.parse(event.body); const dataType = bodyContent.dataType; const webAuth = new CustomJwt(); const decodedToken = webAuth.decodeToken(event.headers.Authorization); const userUUID = decodedToken['uuid']; const connection = new MySqlConnect(); let sql; switch (dataType) { case 'userPreferences': sql = await connection.queryDb('SELECT * FROM user WHERE uuid = ?', [userUUID]); break; } let data = []; for (let index in sql) { data.push(JSON.parse(JSON.stringify(sql[index]))); } const returnData = { data }; let compressed = compress(returnData); response.statusCode = responseCode; response.body = JSON.stringify(compressed); return response; };
问题分析与解决方案
1. 修复MySQL连接错误的Promise处理
当前connection.connect的错误分支仅打印日志,未reject Promise,导致Promise长期处于pending状态,触发Lambda超时或资源泄漏,最终引发502。
修复代码:
connection.connect(function (err) { if (err) { console.log('error when connecting to db:', err); return reject(err); // 新增:传递连接错误 } else { console.log('Connected'); connection.query(sql, args, function (err, result) { connection.end(); if (err) { return reject(err); } return resolve(result); }); } });
2. 改用MySQL连接池替代单次连接
每次请求创建新连接会导致连接数过载、释放不及时,是超时错误的核心原因。改用连接池自动管理连接生命周期:
修改后的MySQL连接器代码:
const CustomSecret = require('../secrets/CustomSecret'); const mysql = require("mysql"); module.exports = class MySqlConnect { pool; databaseCredObject; constructor() {} async getPool() { if (!this.databaseCredObject) { await this.fetchSecret(); } if (!this.pool) { this.pool = mysql.createPool({ host: this.databaseCredObject.host, user: this.databaseCredObject.username, password: this.databaseCredObject.password, database: 'logbook', connectionLimit: 10, // 根据并发量调整 acquireTimeout: 10000 // 限制连接等待时长 }); } return this.pool; } async queryDb(sql, args) { const pool = await this.getPool(); return new Promise((resolve, reject) => { pool.query(sql, args, (err, result) => { if (err) { return reject(err); } resolve(result); }); }); } async fetchSecret() { const databaseCredString = await CustomSecret.getSecret('secretname', 'eu-west-2'); this.databaseCredObject = JSON.parse(databaseCredString); } }
3. 全局捕获Lambda异常,避免进程崩溃
未捕获的异常会直接终止Lambda进程,引发Runtime.ExitError(段错误多为未处理异常的连锁反应)。在handler外层添加try/catch包裹:
修改后的Lambda handler:
const {compress, decompress} = require("compress-json"); const MySqlConnect = require("customPackagePath/MySqlConnect"); const CustomJwt = require("customPackagePath/CustomJwt"); const AWS = require("aws-sdk"); const warmer = require("lambda-warmer"); exports.handler = async (event) => { try { if (await warmer(event)) { console.log("Warming"); return 'warmed'; } let responseCode = 200; let response = {}; response.headers = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }; const bodyContent = JSON.parse(event.body); const dataType = bodyContent.dataType; const webAuth = new CustomJwt(); const decodedToken = webAuth.decodeToken(event.headers.Authorization); const userUUID = decodedToken['uuid']; const connection = new MySqlConnect(); let sqlResult; switch (dataType) { case 'userPreferences': sqlResult = await connection.queryDb('SELECT * FROM user WHERE uuid = ?', [userUUID]); break; default: throw new Error('Invalid dataType provided'); } let data = []; for (let index in sqlResult) { data.push(JSON.parse(JSON.stringify(sqlResult[index]))); } const returnData = { data }; let compressed = compress(returnData); response.statusCode = responseCode; response.body = JSON.stringify(compressed); return response; } catch (err) { console.error('Lambda handler error:', err); // 返回标准错误响应,避免API Gateway返回502 return { statusCode: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ error: 'Internal server error' }) }; } };
4. Lambda-warmer的优化
lambda-warmer本身无问题,但需确保预热请求不触发数据库连接逻辑。当前代码已在warmer分支返回后才初始化连接,无需额外修改;若后续扩展预热逻辑,避免执行数据库操作即可。
5. 解决段错误(segmentation fault)
- 升级mysql包:旧版mysql包存在已知bug,建议升级至最新稳定版,或替换为更可靠的
mysql2包 - 检查Lambda运行时:使用AWS支持的Node.js版本(如18.x或20.x),规避过时runtime的底层bug
内容的提问来源于stack exchange,提问作者PilotPatel
相关产品推荐
相关产品推荐

