Browse docs

Monitor cron jobs in NestJS

Integrate WatchCat with NestJS scheduled tasks to get alerted when a job misses a run or throws an unhandled error.

NestJS uses the @nestjs/schedule package to run methods on a cron schedule. Like most schedulers, it runs silently — exceptions are swallowed by default and there's no alerting when a task stops running. A WatchCat ping at the end of each task gives you that coverage.

Step 1 — create a cron monitor

In WatchCat, go to Cron monitors → New monitor. Set the schedule to match your task's frequency and add a grace period of a few minutes. Copy the ping URL.

Step 2 — install and register the schedule module

If you haven't already, install the package:

npm install @nestjs/schedule

Then import ScheduleModule in your root module:

import { ScheduleModule } from '@nestjs/schedule';

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

Step 3 — ping after the task runs

Add a @Cron() decorator to a service method and call the ping URL at the end. Node 18+ has fetch built in, so no extra HTTP library is needed.

Using native fetch (Node 18+)

import { Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';

const PING_URL = 'https://watchcat.io/p/cron/YOUR_TOKEN';

@Injectable()
export class ReportService {

  @Cron('0 0 3 * * *')
  async generateDailyReport() {
    // ... your task logic ...

    await fetch(PING_URL);
  }
}

Using Axios (NestJS HttpModule)

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Cron } from '@nestjs/schedule';
import { firstValueFrom } from 'rxjs';

const PING_URL = 'https://watchcat.io/p/cron/YOUR_TOKEN';

@Injectable()
export class ReportService {
  constructor(private readonly http: HttpService) {}

  @Cron('0 0 3 * * *')
  async generateDailyReport() {
    // ... your task logic ...

    await firstValueFrom(this.http.get(PING_URL));
  }
}
Note: NestJS catches exceptions thrown from scheduled methods and logs them, but doesn't re-throw. This means the method exits without reaching the ping. WatchCat treats the missing ping as a failure once the grace period expires — which is the correct behaviour.

Start and end tracking

For tasks that run for more than a few seconds, use start and end pings wrapped in a try/catch so WatchCat can detect tasks that started but never finished.

const PING = 'https://watchcat.io/p/cron/YOUR_TOKEN';

@Cron('0 */30 * * * *')
async syncOrders() {
  await fetch(`${PING}/start`);

  try {
    // ... your task logic ...

    await fetch(`${PING}/end`);
  } catch (err) {
    await fetch(`${PING}/fail`);
    throw err;
  }
}

Using CronExpression constants

@nestjs/schedule exports a CronExpression enum with named presets as an alternative to writing cron strings by hand:

import { Cron, CronExpression } from '@nestjs/schedule';

@Cron(CronExpression.EVERY_DAY_AT_3AM)
async runNightlyJob() { ... }

@Cron(CronExpression.EVERY_30_MINUTES)
async pollExternalApi() { ... }

NestJS uses a six-field cron expression (with a leading seconds field), matching Spring's format. In WatchCat, set the expected interval to match your task's run frequency — for example, a task that runs every 30 minutes uses an interval of 30 minutes; a task using EVERY_DAY_AT_3AM uses an interval of 1 day.

Recommended settings

Schedule Match your @Cron() frequency
Grace period 2–5 min for most tasks; longer for heavy processing
Alert after 1 missed run for critical tasks; 2 for routine ones

Start monitoring in minutes

Free plan available. No credit card required.