Interface Redis Scheduler Documentation
Overview
Interface Redis Scheduler provides a distributed task scheduling system built on top of Redis. It stores tasks in a Redis sorted set with their due timestamps as scores, enabling precise scheduling and efficient retrieval of tasks that are ready to execute. The scheduler supports automatic retries for failed tasks and coordinates across multiple application instances using Redis pub/sub.
Getting Started
Install the package in your project:
npm install @antelopejs/interface-redis-scheduler
Note: This package depends on
@antelopejs/interface-redis. You must have it installed and configured for the scheduler to connect to Redis.
Core Concepts
The scheduler operates around three main ideas:
- Handlers process tasks of a specific type. Register them with
setHandler()before scheduling any tasks. - Tasks are stored in a Redis sorted set with their due time as the score. When a task is due, the scheduler calls the matching handler.
- Listener monitors the sorted set and executes tasks when they become due. Enable it with
enableListener().
setHandler
The setHandler function registers a handler for a specific task type. Each handler has a unique name and a callback function that receives the task data as a string.
import { setHandler } from "@antelopejs/interface-redis-scheduler";
setHandler("send-email", async (taskInfo) => {
const emailData = JSON.parse(taskInfo);
await sendEmail({
to: emailData.recipient,
subject: emailData.subject,
body: emailData.body,
});
});
Handler names must not contain the : character, as the scheduler uses it internally as a delimiter.
Parameters
| Parameter | Type | Description |
|---|---|---|
handlerName | string | Unique identifier for the task type |
handler | (taskInfo: string) => void | Promise<void> | Function that processes the task |
enableListener
The enableListener function starts the task execution loop. It creates a dedicated Redis subscriber connection to receive real-time notifications when new tasks are added, and sets up a timer to check for due tasks.
import { enableListener } from "@antelopejs/interface-redis-scheduler";
async function startApp() {
// Register all handlers first
// ...
// Then start the listener
await enableListener();
console.log("Scheduler is active");
}
Important: Register all task handlers before calling
enableListener(). The listener begins processing tasks immediately.
disableListener
The disableListener function stops the scheduler from processing any further tasks. Call it during application shutdown.
import { disableListener } from "@antelopejs/interface-redis-scheduler";
async function stopApp() {
await disableListener();
console.log("Scheduler stopped");
}
addTask
The addTask function schedules a task for execution at a specific time. The task is stored in a Redis sorted set with the due time as its score.
import { addTask } from "@antelopejs/interface-redis-scheduler";
async function scheduleReminder(userId: string) {
// Schedule for 3 days from now
const dueTime = Date.now() + 3 * 24 * 60 * 60 * 1000;
const taskInfo = JSON.stringify({
userId,
type: "password_reminder",
createdAt: new Date().toISOString(),
});
await addTask("send-email", dueTime, taskInfo);
}
The function throws an error if the specified handler name has not been registered.
Parameters
| Parameter | Type | Description |
|---|---|---|
handlerName | string | The registered handler name that processes this task |
dueTime | number | Unix timestamp in milliseconds when the task should execute |
taskInfo | string | Data passed to the handler (typically a JSON-encoded string) |
removeTask
The removeTask function cancels a previously scheduled task. The taskInfo string must match the one used when the task was added.
import { removeTask } from "@antelopejs/interface-redis-scheduler";
async function cancelReminder(userId: string) {
const taskInfo = JSON.stringify({
userId,
type: "password_reminder",
createdAt: "2025-04-05T12:00:00.000Z", // Must match exactly
});
await removeTask("send-email", taskInfo);
}
The function throws an error if the specified handler name has not been registered.
Warning: The
taskInfomust be an exact string match of the original task. If the serialized JSON differs in key order or whitespace, the removal fails silently.
Parameters
| Parameter | Type | Description |
|---|---|---|
handlerName | string | The handler name associated with the task |
taskInfo | string | The exact task info string used when adding the task |
Retry Logic
The scheduler automatically retries failed tasks. When a handler throws an error, the scheduler reschedules the task with a retry counter.
- Maximum retries: 3 attempts
- Retry delay: 5 seconds between each attempt
- Behavior on exhaustion: After 3 failed retries, the task is discarded and the error is logged to the console
No additional code is required to enable retries. The mechanism is built into the task execution loop.
import { setHandler } from "@antelopejs/interface-redis-scheduler";
// If this handler throws, the scheduler retries up to 3 times
setHandler("process-payment", async (taskInfo) => {
const data = JSON.parse(taskInfo);
await processPayment(data);
// On failure: retry after 5s, then 5s, then 5s, then discard
});
Redis Storage
The scheduler uses a single Redis sorted set with the key SchedulerUtil.Tasks. Each member in the sorted set follows the format handlerName:taskInfo, and its score is the due timestamp in milliseconds.
For retried tasks, the format becomes RETRY-{count}:handlerName:taskInfo, where {count} tracks the number of retry attempts.
The scheduler also uses a Redis pub/sub channel named SchedulerUtil to notify listener instances when new tasks are added, ensuring timers are updated across all nodes in a cluster.
updateTimer
The updateTimer function refreshes the internal timer that tracks the next due task. The scheduler calls this function automatically when tasks are added or completed. You do not need to call it in normal usage.
import { updateTimer } from "@antelopejs/interface-redis-scheduler";
// Force a timer refresh (advanced usage)
await updateTimer();
runTasks
The runTasks function executes all tasks that are currently due. The scheduler calls this function automatically when the timer fires. It includes the retry logic for failed tasks. You do not need to call it in normal usage.
import { runTasks } from "@antelopejs/interface-redis-scheduler";
// Manually trigger task execution (advanced usage)
await runTasks();
Complete Example
Here is a full integration example showing handler registration, listener startup, task scheduling, and shutdown.
import {
setHandler,
enableListener,
disableListener,
addTask,
removeTask,
} from "@antelopejs/interface-redis-scheduler";
// 1. Register task handlers
setHandler("send-email", async (taskInfo) => {
const data = JSON.parse(taskInfo);
await sendEmail(data.to, data.subject, data.body);
});
setHandler("cleanup-session", async (taskInfo) => {
const { sessionId } = JSON.parse(taskInfo);
await deleteSession(sessionId);
});
// 2. Start the listener
async function start() {
await enableListener();
}
// 3. Schedule tasks from your application logic
async function onUserSignup(userId: string, email: string) {
// Send a welcome email in 1 hour
const dueTime = Date.now() + 60 * 60 * 1000;
await addTask(
"send-email",
dueTime,
JSON.stringify({ to: email, subject: "Welcome!", body: "Thanks for signing up." }),
);
}
async function onUserLogout(sessionId: string) {
// Clean up session data in 24 hours
const dueTime = Date.now() + 24 * 60 * 60 * 1000;
await addTask(
"cleanup-session",
dueTime,
JSON.stringify({ sessionId }),
);
}
// 4. Stop the listener on shutdown
async function shutdown() {
await disableListener();
}