You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS API Gateway随机502错误伴Lambda运行时段错误排查求助

问题排查:AWS Lambda + API Gateway 随机502错误

问题现象

  • 通过API Gateway调用Node.js Lambda函数,频繁随机返回502错误,立即重试相同请求可获得正常响应
  • 日志记录两类错误:
    1. Runtime exited with error: signal: segmentation fault Runtime.ExitError
    2. 带有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 16:35:17