Promise内无法捕获异常:AWS Aurora MySQL连接重试逻辑失效问题排查求助
问题分析与修复方案
你的代码主要有几个核心问题导致重试逻辑没生效,我来逐一拆解:
1. 异步回调的错误无法被外层try/catch捕获
this.cPool.query是基于回调的异步操作,回调函数里的throw err不在createPool的Promise执行器的同步代码栈里,所以外层的try/catch根本抓不到这个错误,它会直接抛出到全局环境导致进程退出,这就是你看到直接报错退出的原因。
2. Promise提前resolve,未等待测试连接结果
你在创建完连接池后立刻设置this.cPoolInit = true并resolve了Promise,但此时测试连接的query还没执行完成。这意味着无论测试连接成功与否,createPool的Promise都会直接resolve,不会进入catch分支触发重试逻辑。
3. 重试时无法重新创建连接池
第一次进入createPool后,this.cPoolInit被设为true,后续重试调用createPool时,会直接跳过创建池的逻辑,一直用之前创建的错误池对象去测试连接,自然无法成功。
修复后的代码
我推荐改用mysql2/promise(原生支持Promise,比回调更易维护),同时调整重试逻辑,确保测试连接完成后再处理Promise状态,并且重试时能重新创建连接池:
import mysql from 'mysql2/promise'; // 改用mysql2/promise版本 export class DatabaseConnectionFactory { private cPool: mysql.Pool | null = null; private cPoolInit: boolean = false; public async initConnection() { try { await this.createPool(); console.log('连接池初始化完成'); } catch (err) { console.error('最终初始化失败:', err); throw err; // 向上抛出错误,让调用方处理 } } private async createPool(attempt: number = 1): Promise<void> { try { // 每次重试都重新创建连接池(如果之前的池存在,先销毁) if (this.cPool) { await this.cPool.end(); this.cPool = null; } this.cPool = mysql.createPool({ connectionLimit: 500, host: "mysqlHost", port: "mysqlPort", user: "mysqlUser", password: "mysqlPassword" }); // 使用Promise化的query测试连接,await等待结果 await this.cPool.query('SHOW DATABASES;'); console.log(`第${attempt}次尝试,测试连接成功`); this.cPoolInit = true; } catch (err) { console.error(`第${attempt}次尝试失败:`, err); if (attempt >= 3) { // 达到最大重试次数,抛出错误 throw new Error(`连接重试3次均失败: ${(err as Error).message}`); } // 根据重试次数设置等待时间 const waitTime = [30, 20, 10][attempt - 1]; console.log(`等待${waitTime}秒后进行第${attempt + 1}次重试`); await this.wait(waitTime); // 递归调用createPool,继续重试 await this.createPool(attempt + 1); } } private wait(seconds: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, seconds * 1000)); } // 对外提供获取连接池的方法 public getPool(): mysql.Pool { if (!this.cPool || !this.cPoolInit) { throw new Error('连接池未初始化,请先调用initConnection'); } return this.cPool; } }
关键修复点说明
- 改用mysql2/promise:原生支持Promise,避免回调嵌套和错误捕获问题,
query方法直接返回Promise,用await就能等待结果。 - 重试时销毁旧连接池:每次重试都重新创建连接池,避免复用之前的错误连接配置。
- 等待测试连接结果后再处理状态:只有当
query成功执行后,才标记cPoolInit = true,否则进入catch分支处理重试。 - 简化重试逻辑:用数组对应重试次数的等待时间,递归调用
createPool直到达到最大重试次数,此时直接抛出错误。 - 增加getPool方法:确保外部只能获取已初始化完成的连接池,避免使用未就绪的池。
这样修改后,当模拟连接失败时,代码会按照30秒、20秒、10秒的间隔重试3次,全部失败后才抛出最终错误,符合你的预期。
内容的提问来源于stack exchange,提问作者S7H
相关产品推荐
相关产品推荐

