diff --git a/README.md b/README.md index 0500b26..4893510 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,26 @@ cronx 'echo hello world from the future' -n "every tuesday at 3pm" # ❯ 0 15 * * 2 ``` +### installation + +Shell (Mac, Linux): + +```bash +curl -fsSL https://raw.githubusercontent.com/polyseam/cronx/main/install.sh | sh +``` + +PowerShell (Windows): + +```powershell +irm https://raw.githubusercontent.com/polyseam/cronx/main/install.ps1 | iex +``` + ## library -### usage +### nlp + +The `nlp` module provides functions for converting between natural language and +cron tab expressions. ```typescript import { @@ -36,16 +53,59 @@ Deno.cron('my job', cronTab, () => { }) ``` -## installation +### cronx -Shell (Mac, Linux): +The `cronx` module provides a simple interface for scheduling cron jobs with +command-line executables or async functions. -```bash -curl -fsSL https://raw.githubusercontent.com/polyseam/cronx/main/install.sh | sh +```typescript +import { + scheduleCronWithExecutable, + scheduleCronWithFunction, +} from "@polyseam/cronx"; + +const expression = "0 15 * * 2"; // every tuesday at 3pm local time +const executable = 'echo "hello world from the future"'; + +scheduleCronWithExecutable(executable, { + cronxEpression: expression, + label: "hello-world", +}); + +scheduleCronWithFunction(async () => { + const res = await fetch("https://api.example.com"); + if (res.ok) { + console.log("service is live!"); + } else { + console.log("service is down!"); + } +}, { + cronxEpression: "* 0,8,16 * * *", // every 8 hours + label: "uptime", + offset: 0, // UTC time is offset=0 +}); ``` -PowerShell (Windows): +### cron -```powershell -irm https://raw.githubusercontent.com/polyseam/cronx/main/install.ps1 | iex +The `cron` module provides helpers for taking user friendly cron expressions and +converting them to [Deno.cron]() compatible expressions. + +```typescript +import { + convertCronxExpressionToDenoCronExpression, + getLocalUTCOffset, +} from "@polyseam/cronx/cron"; + +const worknights = "0 21 * * 0-4"; // Sunday is 0, unlike in Deno.cron + +const timezoneAdjustedCronExpression = + convertCronxExpressionToDenoCronExpression( + worknights, + getLocalUTCOffset(), + ); + +Deno.cron("set-alarms", timezoneAdjustedCronExpression, () => { + console.log("don't forget to set your alarms for tomorrow!"); +}); ``` diff --git a/src/cli.ts b/src/cli.ts index ca815f7..7f064ea 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,27 +1,30 @@ import { Command, ValidationError } from "@cliffy/command"; import { Confirm, Input, Select } from "@cliffy/prompt"; import { colors } from "@cliffy/ansi/colors"; + import type { LogLevel } from "@polyseam/cconsole"; +import deno_json from "../deno.json" with { type: "json" }; + import { cconsole } from "cconsole"; import { runExecutable } from "src/executables.ts"; -import { JobLogger } from "./JobLogger.ts"; - -import deno_json from "../deno.json" with { type: "json" }; +import { JobLogger } from "src/JobLogger.ts"; import { scheduleCronWithExecutable, validateJobLabel } from "src/cronx.ts"; import { getCronTabExpressionForNaturalLanguageSchedule, getNaturalLanguageScheduleForCronTabExpression, -} from "./nlp.ts"; +} from "src/nlp.ts"; + +import { getLocalUTCOffset } from "src/cron.ts"; const DEFAULT_SCHEDULE_OPTIONS = [ { name: "Every minute", value: "* * * * *" }, { name: "Every hour", value: "0 * * * *" }, - { name: "Every day at midnight", value: "0 0 * * *" }, + { name: "Every day at 12am", value: "0 0 * * *" }, { name: "Every 15 minutes", value: "*/15 * * * *" }, { name: "Every 30 minutes", value: "*/30 * * * *" }, { name: "Every Sunday at 12am", value: "0 0 * * 0" }, @@ -41,7 +44,7 @@ export const cli = new Command().name("cronx") "Natural language description of schedule (e.g., 'every day at 2pm')", ) .option("--offset ", "The timezone offset in hours", { - default: new Date().getTimezoneOffset() / -60, + default: getLocalUTCOffset(), }) .option("-l, --label ", "A label for the job") .option("-v, --verbosity ", "Set the log level", { @@ -73,6 +76,7 @@ export const cli = new Command().name("cronx") const { tab, offset, + suppressStdio, } = options; if (options.label) { @@ -176,14 +180,14 @@ export const cli = new Command().name("cronx") }'(${cronExpression})`, ); - const { suppressStdio } = options; - const jobLogger = new JobLogger(label); if (options.run) { cconsole.debug(); cconsole.debug( - `Running job: ${job} ${suppressStdio ? "without" : "with"} stdio`, + `Running job: ${job} ${ + suppressStdio ? "and suppressing output to" : "writing output to" + } stdout and stderr`, ); cconsole.debug(); await runExecutable(job, { diff --git a/src/cron.ts b/src/cron.ts index 4d47da7..2534bdc 100644 --- a/src/cron.ts +++ b/src/cron.ts @@ -141,3 +141,11 @@ export function convertCronxExpressionToDenoCronExpression( offset, ); } + +/** + * Gets the local timezone offset in hours. + * + * @returns The local timezone offset in hours (e.g., -5 for EST, +1 for CET) + */ +export const getLocalUTCOffset = + (): number => (new Date().getTimezoneOffset() / -60); diff --git a/src/nlp.test.ts b/src/nlp.test.ts index c4d6131..46d8001 100644 --- a/src/nlp.test.ts +++ b/src/nlp.test.ts @@ -348,6 +348,12 @@ Deno.test("Monthly and yearly patterns", async (t) => { ), "0 20 * * 6", ); + assertEquals( + getCronTabExpressionForNaturalLanguageSchedule( + "wednesdays and fridays at 3:30pm", + ), + "30 15 * * 3,5", + ); }); await t.step("yearly patterns", () => {