Introduction
In the past, you may have written individual cron entries on your server for every task you needed to schedule — whether it was sending emails, syncing data, or cleaning up old files. Over time, this becomes hard to manage: your task schedule lives outside your codebase, you lose visibility into what's running and when, and you end up SSHing into your server just to check or update a job.
IntentJS offers a modern, code-first approach to scheduling tasks in your JavaScript or TypeScript apps.
Instead of scattering cron logic across servers or scripts, you define all your recurring tasks in one place — inside your project — using a simple, fluent API. With IntentJS, your entire schedule is part of your source control, versioned alongside your code, and easy to reason about.
When using IntentJS, you only need to register a single cron job on your server or deployment platform. That one entry boots up the IntentJS runtime, which then figures out which tasks should run based on your config.
Defining Schedules
The schedules are defined in the ServiceProvider#schedules class, present inside the app/boot/sp directory To get started, let's take a look at an example. In this example, we will schedule a callback to be called every day at 1PM. Within this callback, we will execute a database query to get count of all users.
import { Schedule } from '@intentjs/core/schedule';
Schedule.call(() => {
const count = db.users.count();
console.log('total number of users ===', count);
}).dailyAt('13:00').run();In addition to scheduling using callback, you may also schedule an Injectable class. These Injectable classes need to have a handle method which will automatically be invoked.
Schedule.call(ClearAbandonedCarts).daily().run();If you would like to see the list of all registered schedules, you can use the schedule:list command.
node intent schedule:listIntent Commands
In addition to scheduling callbacks, you can also schedule Intent Commands and system commands. For example, you may use the command method to schedule an Intent command.
When scheduling an Intent command, you can also pass array of additional command-line arguments that should be provided when it is invoked.
Schedule.command('users:delete-inactive --force')
.purpose('Delete the users inactive for last 30 days')
.daily()
.run();Queued Jobs
If you wish to schedule a Queued Jobs, you can use the job method to do so. It provides a convenient way to schedule queued jobs, without having to use the call method.
Schedule.job({
job: 'process_abandoned_cart',
data: { from: '2024-04-16', to: '2024-04-17' },
})
.purpose('cron dispatching job every day at 5AM')
.at('5 AM')
.run();The job method accepts the same set of arguments that you use when dispatching a job, which means you can also pass the queue name, connection, delay, etc. arguments.
Schedule.job({
job: 'process_abandoned_cart',
data: { from: '2024-04-16', to: '2024-04-17' },
queue: 'cart-queue',
delay: 10 // in seconds
})
.purpose('cron dispatching job every day at 5AM')
.at('5 AM')
.run();Shell Commands
You can use the exec method to issue a command to the operating system.
Schedule.exec('ls -al').daily().run();Frequency Options
Till now, we have already seen a few examples of how you can define a schedule to run at specificed intervals. However, Intent comes with many more schedule frequencies that you can use while defining a task.
| Method | Description |
|---|---|
.cron('* * * * *'); | Set a custom cron expression for the task (e.g., run every minute). |
.at('13:00'); | Schedule the task to run daily at a specific time (e.g., '13:00'). Alias for dailyAt. |
.everySecond(); | Schedule the task to run every second. |
.everyTwoSeconds(); | Schedule the task to run every two seconds. |
.everyFiveSeconds(); | Schedule the task to run every five seconds. |
.everyTenSeconds(); | Schedule the task to run every ten seconds. |
.everyFifteenSeconds(); | Schedule the task to run every fifteen seconds. |
.everyTwentySeconds(); | Schedule the task to run every twenty seconds. |
.everyThirtySeconds(); | Schedule the task to run every thirty seconds. |
.everyMinute(); | Schedule the task to run every minute. |
.everyTwoMinutes(); | Schedule the task to run every two minutes. |
.everyThreeMinutes(); | Schedule the task to run every three minutes. |
.everyFourMinutes(); | Schedule the task to run every four minutes. |
.everyFiveMinutes(); | Schedule the task to run every five minutes. |
.everyTenMinutes(); | Schedule the task to run every ten minutes. |
.everyFifteenMinutes(); | Schedule the task to run every fifteen minutes. |
.everyThirtyMinutes(); | Schedule the task to run every thirty minutes. |
.hourly(); | Schedule the task to run hourly (at minute 0). |
.hourlyAt(15); | Schedule the task to run hourly at a specific minute (e.g., at minute 15). |
.everyOddHour(30); | Schedule the task to run every odd hour, at a specific minute (e.g., at minute 30). |
.everyTwoHours(); | Schedule the task to run every two hours (at minute 0). |
.everyThreeHours(45); | Schedule the task to run every three hours, at a specific minute (e.g., at minute 45). |
.everyFourHours(); | Schedule the task to run every four hours (at minute 0). |
.everySixHours(10); | Schedule the task to run every six hours, at a specific minute (e.g., at minute 10). |
.daily(); | Schedule the task to run daily at midnight. |
.dailyAt('13:00'); | Schedule the task to run daily at a specific time (e.g., '13:00'). |
.twiceDaily(1, 13); | Schedule the task to run twice daily at specified hours (e.g., 1 AM and 1 PM) at minute 0. |
.twiceDailyAt(8, 20, 30); | Schedule the task to run twice daily at specified hours and minute (e.g., 8:30 AM and 8:30 PM). |
.weekly(); | Schedule the task to run weekly on Sunday at midnight. |
.weeklyOn(1, '08:00'); | Schedule the task to run weekly on a specific day (e.g., 1 for Monday) and time (e.g., '08:00'). |
.monthly(); | Schedule the task to run monthly on the 1st at midnight. |
.monthlyOn(4, '15:00'); | Schedule the task to run monthly on a specific day (e.g., the 4th) and time (e.g., '15:00'). |
.twiceMonthly(1, 16, '08:00'); | Schedule the task to run twice monthly on specific days (e.g., the 1st and 16th) and time (e.g., '08:00'). |
.lastDayOfMonth('23:59'); | Schedule the task to run on the last day of the month at a specific time (e.g., '23:59'). |
.quarterly(); | Schedule the task to run quarterly on the 1st of the first month of the quarter at midnight. |
.quarterlyOn(15, '00:00'); | Schedule the task to run quarterly on a specific day of the first month of the quarter (e.g., the 15th) and time (e.g., '00:00'). |
.yearly(); | Schedule the task to run yearly on January 1st at midnight. |
.yearlyOn(6, 1, '17:00'); | Schedule the task to run yearly on a specific month (e.g., 6 for June), day (e.g., 1st), and time (e.g., '17:00'). |
You can also combine these methods to create even more finely tuned schedules that only run on certain days of the week. For example, you may schedule a command to run only on Tuesdays.
// Run once per week on Monday at 1 PM...
Schedule.command('foo')
.weekly()
.mondays()
.at('13:00')
.run();
// Run hourly from 8 AM to 5 PM on weekdays...
Schedule.command('send:email')
.weekdays()
.hourly()
.timezone('America/Chicago')
.between('8:00', '17:00')
.run();A list of additional schedule frequencies can be found below.
| Methods | Description |
|---|---|
.weekdays(); | Limit the task to weekdays. |
.weekends(); | Limit the task to weekends. |
.sundays(); | Limit the task to Sunday. |
.mondays(); | Limit the task to Monday. |
.tuesdays(); | Limit the task to Tuesday. |
.wednesdays(); | Limit the task to Wednesday. |
.thursdays(); | Limit the task to Thursday. |
.fridays(); | Limit the task to Friday. |
.saturdays(); | Limit the task to Saturday. |
.days(array); | Limit the task to specific days. |
.between(startTime, endTime); | Limit the task to run between start and end times. |
.when(callback); | Limit the task based on a truth test. |
.skip(callback); | Limit the task based on a false test. |
Day Constraints
The days method can be used to limit the execution of a task to specific days of a the week. For example, you may schedule a command to run hourly on Monday and Thursday.
Schedule.command('foo')
.hourly()
.days([1, 4])
.run();Alternatively, you may also use the constants available in the Schedule class.
Schedule.command('foo')
.hourly()
.days([Schedule.MONDAY, Schedule.THURSDAY])
.run();Between Time Constraints
You can make use of the between method to limit the execution of a task based on the time of a day.
Schedule.command('foo')
.hourly()
.between('7:00', '22:00')
.run()Truth Test Constraints
There can be scenarios when you want to limit the task based on a result of a given truth test, for this you can utilise the when method, if the callback returns true, the task will execute as long as no other constraining conditions prevent the task from running.
Schedule.command('foo')
.daily()
.when(() => {
return true;
})
.run();If you want to do the inverse of when method, you can use the skip method. If the skip method returns true, the scheduled task will not be executed.
Schedule.command('foo')
.daily()
.skip(() => {
return true;
})
.run();Timezones
Using the timezone method, you can specify that a schedule task's time should be interpreted withing a given timezone.
Schedule.command('foo')
.timezone('America/Chicago')
.at('2:00')
.run();Meta Methods
When you are defining a schedule using the Schedule class, you would want to assign some meta information to it like purpose, name to improve the readability of the Schedule class.
Purpose
To assign a purpose of the scheduled task, you can use the purpose method.
Schedule.command('email:send')
.purpose('Send emails to the newsletter subscribers.')
.daily()
.run();Name
If you wish to dynamically start or stop your scheduled task, it's always recommended to assign a name to your task. The name you provide shall be used against the task in the SchedulerRegistry class.
To assign a name to the task, you can use the name method.
Schedule.command('email:send')
.name('send_email')
.daily()
.run();Running the Scheduler
There are two ways you can run your scheduled tasks, in your main application's thread, or else in a separate thread. By default, the tasks run in the main thread, if you would like to change this behaviour you can change the runInAnotherThread flag in config/app.ts file.
/**
* -----------------------------------------------------
* Scheduler Configuration
* -----------------------------------------------------
*
* This property defines the configuration for the scheduler.
*/
schedules: {
/**
* -----------------------------------------------------
* Run in another thread
* -----------------------------------------------------
*
* This property defines whether the scheduler
* should run in another thread.
*/
runInAnotherThread: true,
/**
* -----------------------------------------------------
* Timezone
* -----------------------------------------------------
*
* This property defines the timezone for the scheduler.
*/
timezone: "Asia/Kolkata",
}Now, to start your schedules in a separate thread, you can run the schedule:work command. This approach is beneficial if you are running your application on multiple servers, then you would want to limit your scheduled jobs to only be executed on a single server.
node intent schedule:workTask Output
Intent Task Schedulers provides several convenient methods for working with the output generated by the scheduled tasks. First, using the sendOutputTo method, you can send the output to a file for later inspection.
Schedule.command('emails:send')
.daily()
.sendOutputTo(filePath)
.run();If you would like to append the output to a given file, you can use the appendOutputTo method.
Schedule.command('emails:send')
.daily()
.appendOutputTo(filePath)
.run();Using the emailOutputTo method, you can email the output to the specified email address. Before emailing, make sure you have configured Intent's email services.
Schedule.command('report:generate')
.daily()
.sendOutputTo(filePath)
.emailOutputTo('[email protected]')
.run();If you want to email the output only on failure, use the emailOutputOnFailure method.
Schedule.command('report:generate')
.daily()
.emailOutputOnFailure('[email protected]')
.run();Task Hooks
Using the before and after methods, you may specify callbacks to be executed before and after the scheduled task is executed.
Schedule.command('emails:send')
.daily()
.before(() => {})
.after(() => {})
.run();The onSuccess and onFailure method allows you to specify code to be executeed if the scheduled task succeeds or dails.
Schedule.command('emails:send')
.daily()
.onSuccess(() => {})
.onFailure((error: Error) => {})
.run();If output is available from your scheduled task, you may access it in your after, onSuccess or onFailure hooks.
Schedule.command('emails:send')
.daily()
.onSuccess((result: any) => {})
.onFailure((result:any) => {})Pinging URLs
Using the pingBefore and thenPing methods, the scheduler can automatically ping a given URL before or after the task is executed. This method can be useful for notifying on an external service, such as Slack, etc, that your scheduled task is beginning or has finished execution.
Schedule.command('emails:send')
.daily()
.pingBefore(url)
.thenPing(url)
.run();The pingOnSuccess and pingOnFailure methods may be used to ping the given URL only if the task succeeds or fails.
Schedule.command('emails:send')
.daily()
.pingOnSuccess(url)
.pingOnFailure(url)
.run();The pingBeforeIf, thenPingIf, pingOnSuccessIf, and pingOnFailureIf methods may be used to ping a given URL only if the given callback returns true.
Schedule.command('emails:send')
.daily()
.pingBeforeIf(() => true, beforePingUrl)
.thenPingIf(() => true, thenPingUrl)
.run();
Schedule.command('emails:send')
.daily()
.pingOnSuccessIf(() => true, pingOnSuccessUrl)
.pingOnFailureIf(() => true, pingOnFailureUrl)
.run();