Files
skills/docs/communication/messaging/notification-channel/src/scheduler/notification-scheduler.md
2026-05-29 08:20:56 +01:00

2.8 KiB

notification-scheduler — Future-delivery scheduler

(no submodules)

Purpose

notification-scheduler.ts ships the NotificationScheduler class for scheduling notifications for future delivery. The scheduler does NOT call the router itself — callers register an onDue(handler) that receives the original NotificationInput, typically wiring it back into NotificationRouter.send or enqueue. The class exposes both manual processDue() (call from cron / queue worker) and start()/stop() for in-process polling.

Features

  • schedule(input, deliverAt) returns a stable id.
  • cancel(id), get(id), listPending(), getDue(now?) for inspection.
  • processDue() awaits the handler per entry and removes processed entries.
  • start()/stop() polling driver with idempotent semantics.
  • Injectable Clock for deterministic tests.
  • Throws NotificationNotFoundError for unknown ids on cancel / get.

Usage: Basic

import {
    NotificationRouter,
    NotificationScheduler,
} from "@suaveplan/notification-channel";

const router = new NotificationRouter({ channels, defaultChannel: "email" });
const scheduler = new NotificationScheduler();
scheduler.onDue(async (input) => {
    await router.send(input);
});
scheduler.schedule({ recipient: "u@x", body: "Reminder" }, new Date(Date.now() + 60_000));
scheduler.start();

Usage: Advanced

const scheduler = new NotificationScheduler(5_000, () => clock.now());
scheduler.onDue(async (input) => {
    try {
        await router.send(input);
    } catch (err) {
        await failureQueue.push({ input, err });
    }
});

// Hook into a cron worker instead of in-process polling:
cron.schedule("* * * * *", () => {
    void scheduler.processDue();
});

API Reference

  • NotificationScheduler(checkIntervalMs?, clock?) — constructor.
  • schedule(input, deliverAt), cancel(id), get(id), listPending(), getDue(now?), processDue(), start(), stop(), size.
  • ScheduledNotification — { id, input, scheduledFor, createdAt, cancelled }.
  • ScheduleHandler — (input: NotificationInput) => Promise<void>.

Implementation Notes

start() is idempotent — calling twice has no effect; the second call is dropped before setInterval runs. stop() is idempotent — calling twice is safe and a leading call before start() is a no-op. processDue() is the single place that mutates the schedule map — both the polling driver and manual / cron callers use it, so behaviour is identical regardless of how processing is triggered. The scheduler does not persist across process restarts — production deployments should layer their own durable store atop schedule/cancel (e.g. snapshot listPending() to disk on shutdown, restore on boot via additional schedule calls).