Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Scheduled tasks

Some actions must run on their own, without a client request: a nightly report, cleaning up stale data, a mailing. The @nestjs/schedule module lets you mark a service method with a decorator, and NestJS calls it on schedule while the server is running.

Installation and setup

npm i @nestjs/schedule
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { PostsModule } from './posts/posts.module';
 
@Module({
  imports: [ScheduleModule.forRoot(), PostsModule],
})
export class AppModule {}

ScheduleModule.forRoot() is added once, in the root module. It then finds marked methods in every service.

A scheduled task

Let the blog log every night how many posts appeared during the day. Create a service:

nest g service posts/posts-report --flat
// src/posts/posts-report.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { MoreThan, Repository } from 'typeorm';
import { Post } from './entities/post.entity';
 
@Injectable()
export class PostsReportService {
  private readonly logger = new Logger(PostsReportService.name);
 
  constructor(
    @InjectRepository(Post)
    private readonly postsRepository: Repository<Post>,
  ) {}
 
  @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
  async dailyReport() {
    const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
    const count = await this.postsRepository.count({ where: { createdAt: MoreThan(since) } });
    this.logger.log(`New posts in the last day: ${count}`);
  }
}

Every day at midnight the server terminal shows a line like [PostsReportService] New posts in the last day: 3. MoreThan() from TypeORM sets a "greater than" condition. The Logger class is covered in the next lesson.

Cron syntax

Instead of the ready constants you can write a cron string — five or six space-separated fields:

* * * * * *
│ │ │ │ │ └─ day of week (0–7)
│ │ │ │ └─── month (1–12)
│ │ │ └───── day of month (1–31)
│ │ └─────── hour (0–23)
│ └───────── minute (0–59)
└─────────── second (0–59, optional)
NotationWhen it fires
@Cron('0 */10 * * * *')Every 10 minutes
@Cron('0 0 9 * * 1')Mondays at 9:00
@Cron(CronExpression.EVERY_HOUR)At the start of every hour

To run a task in a particular time zone, add a second argument: @Cron('0 0 9 * * 1', { timeZone: 'Europe/Berlin' }).

Intervals and one-off runs

// src/posts/posts-report.service.ts
import { Interval, Timeout } from '@nestjs/schedule';
 
@Interval(60_000)
checkQueue() {
  this.logger.log('Checking the queue');
}
 
@Timeout(5_000)
warmUp() {
  this.logger.log('The server started five seconds ago');
}

@Interval() calls the method every 60 seconds, counting from server start. @Timeout() calls the method once, five seconds after start.

Common mistake

If you run several copies of the server (for example, to handle load), the task runs in each copy — the report arrives three times and emails go out three times. The schedule in @nestjs/schedule lives inside the process and knows nothing about other copies. With several servers, run tasks in one separate process or use a job queue.

Thanks for reading!

Donate to the site — we work hard for you.