NestJS中实现动态Cron任务管理

引言

任务调度是现代后端应用中的常见需求,无论是定时数据清理、报表生成还是系统维护,都需要可靠的任务调度机制。NestJS通过@nestjs/schedule包提供了强大的任务调度功能,但官方文档主要关注静态任务配置。本文将带你探索如何在NestJS中实现动态的Cron任务管理,包括添加、修改和移除任务。

核心概念

1. @nestjs/schedule模块

@nestjs/schedule是NestJS官方提供的任务调度模块,基于流行的node-cron库。它提供了:

  • @Cron()装饰器:声明静态Cron任务
  • SchedulerRegistry:用于管理已注册的任务
  • 间隔任务和超时任务支持

2. 动态任务 vs 静态任务

  • 静态任务:在应用启动时通过装饰器定义,生命周期与应用一致
  • 动态任务:可在运行时添加、修改和删除,灵活性更高

实现步骤

1. 基础配置

首先安装依赖:

bash 复制代码
npm install @nestjs/schedule

然后在AppModule中导入:

typescript 复制代码
import { ScheduleModule } from '@nestjs/schedule';

@Module({
  imports: [ScheduleModule.forRoot()],
})
export class AppModule {}

2. 创建动态任务服务

核心服务DynamicTaskService封装了所有动态任务操作:

typescript 复制代码
@Injectable()
export class DynamicTaskService {
  constructor(private schedulerRegistry: SchedulerRegistry) {}

  // 添加任务
  addCronJob(name: string, cronTime: string, callback: () => void) {
    const job = new CronJob(cronTime, callback);
    this.schedulerRegistry.addCronJob(name, job);
    job.start();
  }

  // 检查任务是否存在
  doesCronJobExist(name: string): boolean {
    try {
      this.schedulerRegistry.getCronJob(name);
      return true;
    } catch {
      return false;
    }
  }

  // 更新任务
  updateCronJob(name: string, cronTime: string, callback: () => void) {
    this.deleteCronJob(name);
    this.addCronJob(name, cronTime, callback);
  }

  // 删除任务
  deleteCronJob(name: string) {
    this.schedulerRegistry.deleteCronJob(name);
  }

  // 获取所有任务
  getCronJobs() {
    return Array.from(this.schedulerRegistry.getCronJobs().entries())
      .map(([name, job]) => ({
        name,
        cronTime: job.cronTime.source,
        running: job.running,
        lastExecution: job.lastDate(),
      }));
  }
}

3. 创建任务管理API

通过REST API暴露任务管理功能:

typescript 复制代码
@Controller('tasks')
export class TasksController {
  constructor(private readonly taskService: DynamicTaskService) {}

  @Post()
  createOrUpdateTask(@Body() body: { name: string; cronTime: string }) {
    const taskLogic = () => console.log(`Executing ${body.name}`);
    
    if (this.taskService.doesCronJobExist(body.name)) {
      this.taskService.updateCronJob(body.name, body.cronTime, taskLogic);
      return { message: 'Task updated' };
    } else {
      this.taskService.addCronJob(body.name, body.cronTime, taskLogic);
      return { message: 'Task created' };
    }
  }

  @Get()
  listTasks() {
    return this.taskService.getCronJobs();
  }

  @Delete(':name')
  removeTask(@Param('name') name: string) {
    this.taskService.deleteCronJob(name);
    return { message: 'Task deleted' };
  }
}

实际应用示例

1. 创建每日数据备份任务

bash 复制代码
POST /tasks
{
  "name": "daily-backup",
  "cronTime": "0 3 * * *"  # 每天凌晨3点执行
}

2. 修改为每周备份

bash 复制代码
POST /tasks
{
  "name": "daily-backup",
  "cronTime": "0 3 * * 1"  # 改为每周一凌晨3点
}

3. 查看所有任务

bash 复制代码
GET /tasks

# 返回示例
[
  {
    "name": "daily-backup",
    "cronTime": "0 3 * * 1",
    "running": true,
    "lastExecution": "2023-05-15T03:00:00.000Z"
  }
]

高级主题

1. 任务持久化

内存中的任务会在应用重启后丢失,解决方案:

typescript 复制代码
// 启动时从数据库加载任务
async onApplicationBootstrap() {
  const savedTasks = await this.taskRepository.find();
  savedTasks.forEach(task => {
    this.addCronJob(task.name, task.cronTime, this.getTaskLogic(task));
  });
}

2. 分布式环境考虑

在多实例部署中,需要:

  • 使用分布式锁确保任务只在一个实例执行
  • 考虑使用专门的作业队列系统(如BullMQ)
  • 或者使用数据库标记防止重复执行

3. 错误处理与监控

增强健壮性:

typescript 复制代码
addCronJob(name: string, cronTime: string, callback: () => void) {
  try {
    const job = new CronJob(cronTime, () => {
      try {
        callback();
      } catch (error) {
        this.logger.error(`Job ${name} execution failed`, error.stack);
      }
    });
    // ...其余代码
  } catch (error) {
    this.logger.error(`Invalid cron pattern: ${cronTime}`);
    throw new BadRequestException('Invalid cron pattern');
  }
}

总结

通过@nestjs/scheduleSchedulerRegistry,我们可以在NestJS中实现灵活的动态任务管理。关键点包括:

  1. 使用CronJob类创建动态任务
  2. 通过SchedulerRegistry管理任务生命周期
  3. 提供清晰的API进行任务CRUD操作
  4. 考虑持久化和分布式场景

这种模式非常适合需要动态调整任务调度策略的应用,如CMS系统、数据分析平台等。根据你的具体需求,可以进一步扩展错误处理、监控和持久化功能。

相关推荐
RoyLin9 小时前
TypeScript设计模式:适配器模式
前端·后端·node.js
RoyLin14 小时前
TypeScript设计模式:迭代器模式
javascript·后端·node.js
轻松Ai享生活16 小时前
5 节课深入学习Linux Cgroups
linux
christine-rr17 小时前
linux常用命令(4)——压缩命令
linux·服务器·redis
三坛海会大神55517 小时前
LVS与Keepalived详解(二)LVS负载均衡实现实操
linux·负载均衡·lvs
東雪蓮☆17 小时前
深入理解 LVS-DR 模式与 Keepalived 高可用集群
linux·运维·服务器·lvs
乌萨奇也要立志学C++18 小时前
【Linux】进程概念(二):进程查看与 fork 初探
linux·运维·服务器
前端双越老师18 小时前
2025 年还有前端不会 Nodejs ?
node.js·agent·全栈
绿箭柠檬茶19 小时前
Ubuntu 服务器配置转发网络访问
服务器·网络·ubuntu
风_峰19 小时前
Ubuntu Linux SD卡分区操作
嵌入式硬件·ubuntu·fpga开发