Nest-Commander执行TypeORM数据填充时报错:连接关闭无法添加命令
问题排查:TypeORM连接关闭状态下无法创建ApplicationStatus
问题场景
数据库存在Applications表,通过TypeORM与ApplicationStatus表建立一对一关联。使用nest-commander编写命令为所有应用填充状态,命令隶属于导入到AppModule的ApplicationModule。运行命令时,获取Application数据正常,但创建ApplicationStatus时抛出错误:"Can't add new command when connection is in closed state"。
相关代码
seed-applications-status.command.ts
constructor( @InjectRepository(Application) private applicationRepository: Repository<Application>, private readonly applicationService: ApplicationService, private readonly applicationStatusService: ApplicationStatusService, ) { super(); } async run(inputs: string[], options: Record<string, any>): Promise<void> { /* Works.. */ const applications = await this.applicationService.findAll(); /* doesn't work.. */ applications.forEach(async (application: Application) => { const applicationStatus = await this.applicationStatusService.create( application, ); application.status = applicationStatus; this.applicationRepository.save(application); }); return; }
application-status.service.ts
constructor( @InjectRepository(ApplicationStatus) private readonly applicationStatusRepository: Repository<ApplicationStatus>, ) {} async create(application: Application) { const applicationStatus = this.applicationStatusRepository.create({ status: 'PENDING', cnieStatus: 'PENDING', schoolCertificateStatus: 'PENDING', regulationsStatus: 'PENDING', gradesStatus: 'PENDING', }); applicationStatus.application = application; await this.applicationStatusRepository.save(applicationStatus); return applicationStatus; }
main-cli.ts
async function bootstrap() { await CommandFactory.run(AppModule, { logger: ['warn', 'error'], }); } bootstrap();
问题原因
核心问题在于run方法中使用了forEach遍历异步操作,forEach不会等待内部的异步任务完成。当所有forEach循环结束后,run方法直接返回,nest-commander认为命令执行完毕,会立即关闭数据库连接。但此时forEach内部的create和save异步操作还在后台执行,导致在已关闭的连接上执行数据库命令,抛出连接关闭的错误。
解决方案
方案1:顺序执行异步任务(for...of)
将forEach替换为for...of循环,确保所有异步操作按顺序执行完毕后,run方法才返回,避免连接提前关闭:
async run(inputs: string[], options: Record<string, any>): Promise<void> { const applications = await this.applicationService.findAll(); // 使用for...of替代forEach,等待每个异步操作完成 for (const application of applications) { const applicationStatus = await this.applicationStatusService.create(application); application.status = applicationStatus; await this.applicationRepository.save(application); // 等待保存操作完成 } return; }
方案2:并行执行异步任务(Promise.all)
如果希望提升执行效率,可使用Promise.all并行处理所有异步任务,等待全部完成后再结束命令:
async run(inputs: string[], options: Record<string, any>): Promise<void> { const applications = await this.applicationService.findAll(); // 收集所有异步任务,并行执行并等待全部完成 await Promise.all(applications.map(async (application) => { const applicationStatus = await this.applicationStatusService.create(application); application.status = applicationStatus; return this.applicationRepository.save(application); })); return; }
内容的提问来源于stack exchange,提问作者Achraf El Khamsi
相关产品推荐
相关产品推荐

