Skip to main content

Schedule

Schedule recurring tasks easily using Cron expressions, intervals, or timeouts.

Installation

bun install @carno.js/schedule

Setup

Register the module in your application.

import { Carno } from '@carno.js/core';
import { CarnoScheduler } from '@carno.js/schedule';

const app = new Carno()
.use(CarnoScheduler);

await app.listen(3000);

Decorators

@Schedule(cronTime, options?)

Schedules a method using a Cron expression. The method runs repeatedly according to the cron schedule.

import { Service } from '@carno.js/core';
import { Schedule, CronExpression } from '@carno.js/schedule';

@Service()
export class TasksService {

@Schedule('0 * * * *')
handleEveryHour() {
console.log('Runs at the start of every hour');
}

// Using the CronExpression helper
@Schedule(CronExpression.EVERY_5_SECONDS)
handleEvery5Seconds() {
console.log('Runs every 5 seconds');
}

// With options
@Schedule(CronExpression.EVERY_DAY_AT_MIDNIGHT, { name: 'nightly-cleanup', timeZone: 'America/Sao_Paulo' })
handleNightlyCleanup() {
console.log('Runs every day at midnight in São Paulo');
}
}

Options (CronOptions):

OptionTypeDescription
namestringName for the job, used to retrieve it from SchedulerRegistry.
timeZonestringTimezone for execution (e.g. 'America/Sao_Paulo'). Cannot be used together with utcOffset.
utcOffsetnumberUTC offset in minutes instead of a timezone name. Cannot be used together with timeZone.
disabledbooleanWhen true, the job is registered but will not run. Defaults to false.
unrefTimeoutbooleanAllows the Node.js process to exit even if the job is still scheduled. Defaults to false.

@Interval(timeout) / @Interval(name, timeout)

Schedules a method using setInterval. The method runs repeatedly at a fixed millisecond interval.

import { Service } from '@carno.js/core';
import { Interval } from '@carno.js/schedule';

@Service()
export class TasksService {

// Anonymous interval – runs every 10 seconds
@Interval(10_000)
handleEvery10Seconds() {
console.log('Called every 10 seconds');
}

// Named interval – can be managed via SchedulerRegistry
@Interval('heartbeat', 5_000)
handleHeartbeat() {
console.log('Heartbeat every 5 seconds');
}
}

@Timeout(timeout) / @Timeout(name, timeout)

Schedules a method using setTimeout. The method runs once after the specified delay in milliseconds.

import { Service } from '@carno.js/core';
import { Timeout } from '@carno.js/schedule';

@Service()
export class TasksService {

// Anonymous timeout – runs once after 5 seconds
@Timeout(5_000)
handleOnce() {
console.log('Called once after 5 seconds');
}

// Named timeout – can be managed via SchedulerRegistry
@Timeout('startup-check', 3_000)
handleStartupCheck() {
console.log('Startup check after 3 seconds');
}
}

CronExpression

CronExpression is a built-in enum with ready-to-use cron expressions. Import and use it instead of writing raw cron strings.

import { CronExpression } from '@carno.js/schedule';

@Schedule(CronExpression.EVERY_DAY_AT_NOON)
handleDailyReport() { ... }

Available expressions

Seconds

ConstantCronDescription
EVERY_SECOND* * * * * *Every second
EVERY_5_SECONDS*/5 * * * * *Every 5 seconds
EVERY_10_SECONDS*/10 * * * * *Every 10 seconds
EVERY_30_SECONDS*/30 * * * * *Every 30 seconds

Minutes

ConstantCronDescription
EVERY_MINUTE*/1 * * * *Every minute
EVERY_5_MINUTES0 */5 * * * *Every 5 minutes
EVERY_10_MINUTES0 */10 * * * *Every 10 minutes
EVERY_30_MINUTES0 */30 * * * *Every 30 minutes

Hours

ConstantDescription
EVERY_HOUREvery hour
EVERY_2_HOURSEvery 2 hours
EVERY_3_HOURSEvery 3 hours
EVERY_4_HOURSEvery 4 hours
EVERY_6_HOURSEvery 6 hours
EVERY_8_HOURSEvery 8 hours
EVERY_12_HOURSEvery 12 hours

Specific times (daily)

ConstantDescription
EVERY_DAY_AT_1AMEVERY_DAY_AT_11PMDaily at the given hour
EVERY_DAY_AT_NOONDaily at 12:00 PM
EVERY_DAY_AT_MIDNIGHTDaily at 12:00 AM

Weekdays (Monday–Friday)

ConstantDescription
MONDAY_TO_FRIDAY_AT_9AMMon–Fri at 09:00
MONDAY_TO_FRIDAY_AT_09_30AMMon–Fri at 09:30
MONDAY_TO_FRIDAY_AT_12PMMon–Fri at 12:00
MONDAY_TO_FRIDAY_AT_6PMMon–Fri at 18:00
(and many more…)Mon–Fri at various hours

Week / Month / Year

ConstantDescription
EVERY_WEEKEvery week (Sunday midnight)
EVERY_WEEKDAYEvery weekday (Mon–Fri midnight)
EVERY_WEEKENDEvery weekend (Sat & Sun midnight)
EVERY_1ST_DAY_OF_MONTH_AT_MIDNIGHT1st of every month at midnight
EVERY_1ST_DAY_OF_MONTH_AT_NOON1st of every month at noon
EVERY_2ND_MONTHEvery 2 months
EVERY_QUARTEREvery quarter (every 3 months)
EVERY_6_MONTHSEvery 6 months
EVERY_YEAREvery year

Business-hours windows

ConstantDescription
EVERY_30_MINUTES_BETWEEN_9AM_AND_5PMEvery 30 min, 09:00–17:00
EVERY_30_MINUTES_BETWEEN_9AM_AND_6PMEvery 30 min, 09:00–18:00
EVERY_30_MINUTES_BETWEEN_10AM_AND_7PMEvery 30 min, 10:00–19:00

SchedulerRegistry

SchedulerRegistry lets you inspect and manage scheduled jobs at runtime. Inject it into any service.

import { Inject, Service } from '@carno.js/core';
import { SchedulerRegistry } from '@carno.js/schedule';

@Service()
export class AppService {

constructor(private readonly registry: SchedulerRegistry) {}

stopJob() {
this.registry.deleteCronJob('nightly-cleanup');
}

pauseInterval() {
this.registry.deleteInterval('heartbeat');
}

listAllCrons() {
const jobs = this.registry.getCronJobs();
jobs.forEach((job, name) => console.log(name, job.running));
}
}

Cron jobs

MethodDescription
getCronJob(name)Returns the CronJob instance by name. Throws if not found.
getCronJobs()Returns a Map<string, CronJob> with all registered cron jobs.
addCronJob(name, job)Registers a CronJob manually. Throws if name is already taken.
deleteCronJob(name)Stops and removes the cron job by name.
doesExist('cron', name)Returns true if a cron job with that name exists.

Intervals

MethodDescription
getInterval(name)Returns the interval ID by name. Throws if not found.
getIntervals()Returns all registered interval names.
addInterval(name, id)Registers an interval ID manually.
deleteInterval(name)Clears and removes the interval by name.
doesExist('interval', name)Returns true if an interval with that name exists.

Timeouts

MethodDescription
getTimeout(name)Returns the timeout ID by name. Throws if not found.
getTimeouts()Returns all registered timeout names.
addTimeout(name, id)Registers a timeout ID manually.
deleteTimeout(name)Clears and removes the timeout by name.
doesExist('timeout', name)Returns true if a timeout with that name exists.

Complete example

import { Service } from '@carno.js/core';
import { Schedule, Interval, Timeout, CronExpression } from '@carno.js/schedule';

@Service()
export class TasksService {

@Schedule(CronExpression.EVERY_DAY_AT_MIDNIGHT, { name: 'cleanup', timeZone: 'America/Sao_Paulo' })
handleCleanup() {
console.log('Daily cleanup at midnight (São Paulo)');
}

@Schedule(CronExpression.EVERY_30_MINUTES_BETWEEN_9AM_AND_5PM, { name: 'business-sync' })
handleBusinessSync() {
console.log('Sync every 30 min during business hours');
}

@Interval('heartbeat', 5_000)
handleHeartbeat() {
console.log('Heartbeat every 5 seconds');
}

@Timeout('startup', 2_000)
handleStartup() {
console.log('Runs once, 2 seconds after startup');
}
}