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

TypeScript连接AWS Aurora MySQL重试逻辑失效问题排查

问题排查:AWS Aurora MySQL连接重试逻辑未生效

问题描述

我正在为连接AWS Aurora MySQL的TypeScript应用编写重试逻辑,目的是唤醒无服务器数据库,设置了3次重试,间隔分别为55、34、21秒。本地测试时修改MySQL端口,触发了Error: connect ECONNREFUSED 127.0.0.1:3305错误,但执行await createDb('dbName')后立即报错,重试逻辑未生效,请求排查代码问题。

原代码

@injectable()
export class Database {
    private readonly databaseConnectionFactory: DatabaseConnectionFactory;
     
    constructor(@inject(Identifiers.DatabaseConnectionFactory) databaseConnectionFactory: DatabaseConnectionFactory){
         this.databaseConnectionFactory = databaseConnectionFactory;
    }

    public async createDb(dbName: string): Promise<any> {
        console.log('dbconnection before');
        let dbConnection  = await this.databaseConnectionFactory.getDbConnection();
        console.log('dbconnection after');

        let sql = `CREATE DATABASE IF NOT EXISTS ${dbName};`;
        dbConnection.query(sql, function (err, result) {
            if (err) {
                console.log(JSON.stringify(err));
                throw err; // Throwing the error here.
            }
            console.log("Result: " + JSON.stringify(result));
            dbConnection.end();
        });
    }
} 

@injectable()
export class DatabaseConnectionFactory {
    private readonly configParams: ConfigParams;
     
    constructor(@inject(Identifiers.ConfigParams) configParams: ConfigParams){
         this.configParams = configParams;
    }

    public async getDbConnection(attempt: number = 1): Promise<any> {
        try {
            let dbConnection  = mysql.createConnection({
                host: 'mysqlHost',
                port: 3305,
                user: 'mysqlUser',
                password: 'mysqlPassword',
            });
            
            dbConnection.connect(async function(err) {
                if (err){
                    throw err;
                } 
                console.log("Connected!");
            });
            return dbConnection;
        } catch (err){
            console.log('attempt');
            console.log(attempt);
            switch(attempt){
                case 1: {
                    console.log('before wait');
                    await this.wait(55);
                    console.log('after wait');
                    break;
                }
                case 2: {
                    await this.wait(34);
                    break;
                }
                case 3: {
                    await this.wait(21);
                    break;
                }
                default:{
                    throw err;
                }
            }

            await this.getDbConnection(attempt + 1);
        }
    }

    private async wait(seconds: number): Promise<any> {
        const ms = 1000 * seconds;
        console.log('wait');
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

问题排查与修复方案

1. 连接错误无法被捕获,重试逻辑未触发

getDbConnection中使用回调式的dbConnection.connect(),该回调是异步执行的,外层try/catch仅能捕获同步代码错误,连接失败的错误会直接抛出到全局上下文,根本进入不了catch块,导致重试逻辑完全无法执行。

修复:改用Promise化的MySQL连接方式(推荐使用mysql2/promise库,原生支持Promise):

import mysql from 'mysql2/promise';

// 修改getDbConnection方法
public async getDbConnection(attempt: number = 1): Promise<any> {
    try {
        // 直接await创建连接,连接失败会直接进入catch
        const dbConnection = await mysql.createConnection({
            host: 'mysqlHost',
            port: 3305,
            user: 'mysqlUser',
            password: 'mysqlPassword',
        });
        console.log("Connected!");
        return dbConnection;
    } catch (err) {
        // 原有重试逻辑...
        return await this.getDbConnection(attempt + 1); // 必须return递归结果
    }
}

2. 递归重试未返回连接对象

catch块中递归调用getDbConnection(attempt + 1)时未返回该Promise,导致上层await getDbConnection()无法获取递归后的连接结果,且最后一次重试失败时错误无法向上抛出。

修复:在递归调用前添加return:

return await this.getDbConnection(attempt + 1);

3. createDb方法存在异步漏洞

createDb中dbConnection.query使用回调,方法虽标记为async但未等待query完成,且回调内的throw err无法被调用方的try/catch捕获,会引发未处理的Promise拒绝。

修复:将query改为Promise化调用:

public async createDb(dbName: string): Promise<any> {
    console.log('dbconnection before');
    const dbConnection = await this.databaseConnectionFactory.getDbConnection();
    console.log('dbconnection after');

    const sql = `CREATE DATABASE IF NOT EXISTS ${dbName};`;
    try {
        const result = await dbConnection.query(sql);
        console.log("Result: " + JSON.stringify(result));
        await dbConnection.end();
        return result;
    } catch (err) {
        console.log(JSON.stringify(err));
        await dbConnection.end();
        throw err;
    }
}

4. 优化重试逻辑可读性

原switch语句可简化为条件判断,更清晰:

catch (err) {
    console.log(`Attempt ${attempt} failed:`, err);
    if (attempt > 3) {
        throw err; // 超过3次重试,抛出最终错误
    }
    const delays = [55, 34, 21];
    await this.wait(delays[attempt - 1]);
    return await this.getDbConnection(attempt + 1);
}

内容的提问来源于stack exchange,提问作者S7H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:36:33