You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS Cron任务异常:单次调用却重复执行6次

NestJS Cron任务重复执行6次的解决办法

可能的原因

  • 应用启动了6个进程/实例:比如用PM2开启了6个进程、集群模式下未处理单实例Cron逻辑,或是本地不小心重复启动了服务。NestJS的Cron任务会随每个实例启动而触发,多实例自然会导致重复执行。
  • 包含Cron的模块被重复导入:如果在多个模块的imports数组中都导入了带有watcher方法的模块,Nest会创建多个模块实例,每个实例都会触发Cron任务。

针对性解决步骤

1. 检查应用实例数量

  • 本地开发:查看终端是否开启了多个服务进程,关闭多余进程即可。
  • 生产环境(如PM2):修改配置确保仅启动1个实例执行Cron;若必须用多进程,给Cron任务加分布式锁来限制单实例执行。

2. 避免模块重复导入

检查AppModule及其他模块的imports数组,确保带有Cron任务的模块只被导入一次,不要在多个模块中重复导入。

3. 多进程场景用分布式锁确保单实例执行

如果业务需要多进程运行,可借助Redis实现分布式锁,保证同一时间只有一个实例执行Cron任务:

import * as Redis from 'ioredis';
import { Cron, CronExpression } from '@nestjs/schedule';

// 初始化Redis客户端
const redis = new Redis({ host: '你的Redis地址' });

@Injectable()
export class YourService {
  @Cron(CronExpression.EVERY_MINUTE)
  async watcher() {
    const lockKey = 'cron:watcher:lock';
    const lockValue = Date.now().toString();
    const lockExpire = 50; // 锁过期时间(单位:秒),根据任务实际执行时长调整

    // 尝试获取锁
    const acquired = await redis.set(lockKey, lockValue, 'EX', lockExpire, 'NX');
    if (!acquired) {
      console.log('已有实例执行该Cron任务,本次跳过');
      return;
    }

    try {
      // 原有业务逻辑
      const now = new Date();
      const openTravelRequests = await this.getOpenTravelRequestsByDate(now);
      
      // 修复异步遍历问题:map不会等待异步操作完成,改用for...of或Promise.all
      if (openTravelRequests.length) {
        // 顺序执行(适合有依赖的场景)
        for (const otr of openTravelRequests) {
          await this.assignNewBoatToOpenTravelRequests(otr._id);
        }
        // 或并行执行(适合无依赖的场景)
        // await Promise.all(openTravelRequests.map(otr => this.assignNewBoatToOpenTravelRequests(otr._id)));
      }
    } finally {
      // 释放锁,避免死锁
      const currentValue = await redis.get(lockKey);
      if (currentValue === lockValue) {
        await redis.del(lockKey);
      }
    }
  }
}

4. 修复代码中的异步遍历问题

你原本使用map(async)的方式不会等待所有异步操作完成,任务会直接结束,可能引发隐藏问题,建议改成for...of(顺序执行)或Promise.all(并行执行),上述代码已包含该修复。

额外排查点

检查@Module()装饰器的providers数组,确认该服务是否被重复注册,若多个模块都注册了该服务,也会导致多实例触发Cron任务。

内容的提问来源于stack exchange,提问作者Oğuzhan KAYA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 13:05:43