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
相关产品推荐
相关产品推荐

