NestJS定时任务中依赖注入服务未定义问题求助
我之前在NestJS 6.x版本里碰到过几乎一模一样的问题,结合你的代码来看,核心原因是直接使用node-cron时,任务执行的上下文没有和Nest的依赖注入(DI)容器正确绑定——哪怕你用了bind(this),node-cron的调度机制还是会跳出Nest的实例上下文,导致注入的服务全部变成undefined。
下面是我验证过的解决方案,分步骤来:
1. 改用Nest官方的Schedule模块
Nest提供了@nestjs/schedule模块,专门用来处理定时任务,它和Nest的DI系统深度集成,能自动解决上下文绑定的问题,比直接用node-cron靠谱得多。
首先安装兼容你Nest版本的依赖(你的Nest是6.5.3,对应@nestjs/schedule v0.4.x):
npm install @nestjs/schedule@^0.4.0 node-cron
2. 注册Schedule模块到AppModule
修改你的AppModule,导入ScheduleModule.forRoot(),并确保UtilitiesService被声明为provider:
import { Module } from '@nestjs/common'; import { ScheduleModule } from '@nestjs/schedule'; import { AppController } from './app.controller'; import { UtilitiesService } from './path-to/utilities.service'; // 导入你的其他业务模块(UserModule、ReviewModule等) @Module({ imports: [ ScheduleModule.forRoot(), // 初始化调度模块 // 你的其他业务模块,比如UserModule、ReviewModule ], controllers: [AppController], providers: [UtilitiesService], // 确保服务被注册到DI容器 }) export class AppModule {}
3. 重构UtilitiesService使用@Cron装饰器
去掉手动创建node-cron任务的代码,改用Nest提供的@Cron装饰器:
import { Injectable, Logger } from '@nestjs/common'; import { Cron } from '@nestjs/schedule'; import { UserService } from '../user/services/user.service'; import { UserWordService } from '../user/services/user-word.service'; import { ReviewService } from '../review/review.service'; import moment from 'moment'; @Injectable() export class UtilitiesService { private readonly logger = new Logger(UtilitiesService.name); constructor ( private readonly userService: UserService, private readonly userWordService: UserWordService, private readonly reviewService: ReviewService, ) {} // 用@Cron装饰器绑定定时任务,直接使用你的cron表达式 @Cron(environment.cronnJobExpression) public async executeCronJob () { const format = 'YYYY-MM-DD hh:mm:ss'; this.logger.log(`Starting cron job at: ${moment().format(format)}`); try { await this.reviewService.deleteAllDailyReviews(); this.logger.log('Successfully deleted all daily reviews'); } catch (e) { this.logger.error('Failed to delete all daily reviews', e.stack); } let users: any; try { users = await this.userService.getAllUsers(); this.logger.log(`Fetched ${users.length} users successfully`); } catch (e) { this.logger.error('Failed to fetch all users', e.stack); } if (users) { // 你的后续业务逻辑 } } }
为什么之前的方法不行?
你手动用node-cron创建任务时,虽然通过bind(this)绑定了当前实例,但node-cron的任务调度是在Nest的DI容器外部运行的。当任务触发时,执行环境并没有关联到Nest创建的UtilitiesService实例,导致注入的userService、reviewService等全部丢失,变成undefined。而Nest的官方Schedule模块会自动把任务执行上下文绑定到DI容器中的服务实例,从根本上解决这个问题。
另外,不需要再手动调用startJob()了——@Cron装饰器会自动注册并启动任务(除非你配置了disabled: true)。
内容的提问来源于stack exchange,提问作者Harry

