Bots create, list, update and delete schedules (cron_jobs, Bun.cron in UTC); a per-minute cron queues due runs as tasks. Routines, Activity (super admins) and Help get their own rail aside. Help covers familiar problems, starting with signing in to Google through Cookie-Editor over the new Desktop (noVNC) view. Co-Authored-By: Claude Opus 5.5 <[email protected]>
51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
import { AppData } from "@/src/data/app-data";
|
|
import AppError from "./app-error";
|
|
|
|
type Params = {
|
|
/**
|
|
* A Bun.cron expression: 5 fields or a nickname like `@daily`, in UTC.
|
|
*/
|
|
schedule: string;
|
|
/**
|
|
* Unix ms to look from (the next run is after it). Defaults to now.
|
|
*/
|
|
from?: number;
|
|
/**
|
|
* Refuse schedules that run more often than
|
|
* `AppData.CronJobMinIntervalMs`. Set when a schedule is saved.
|
|
*/
|
|
check_interval?: boolean;
|
|
};
|
|
|
|
/**
|
|
* The next run of a schedule after `from`, in unix ms, or null when it
|
|
* never runs again. Throws an `AppError` for an invalid expression (or,
|
|
* with `check_interval`, one that runs too often).
|
|
*/
|
|
export default function nextCronRun({ schedule, from = Date.now(), check_interval }: Params): number | null {
|
|
const expression = schedule.trim() as Bun.CronWithAutocomplete;
|
|
let next: Date | null;
|
|
|
|
try {
|
|
next = Bun.cron.parse(expression, from);
|
|
} catch {
|
|
throw new AppError(
|
|
`"${schedule}" isn't a valid schedule. Use 5 cron fields (minute hour day month weekday, e.g. "0 9 * * MON-FRI") or a nickname like @daily.`,
|
|
);
|
|
}
|
|
|
|
if (!next) return null;
|
|
|
|
if (check_interval) {
|
|
const after = Bun.cron.parse(expression, next);
|
|
|
|
if (after && after.getTime() - next.getTime() < AppData.CronJobMinIntervalMs) {
|
|
throw new AppError(
|
|
`"${schedule}" runs too often. Leave at least ${Math.round(AppData.CronJobMinIntervalMs / 60000)} minutes between runs.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
return next.getTime();
|
|
}
|