Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 68 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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!");
});
```
22 changes: 13 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -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" },
Expand All @@ -41,7 +44,7 @@ export const cli = new Command().name("cronx")
"Natural language description of schedule (e.g., 'every day at 2pm')",
)
.option("--offset <hours:number>", "The timezone offset in hours", {
default: new Date().getTimezoneOffset() / -60,
default: getLocalUTCOffset(),
})
.option("-l, --label <label:string>", "A label for the job")
.option("-v, --verbosity <level:string>", "Set the log level", {
Expand Down Expand Up @@ -73,6 +76,7 @@ export const cli = new Command().name("cronx")
const {
tab,
offset,
suppressStdio,
} = options;

if (options.label) {
Expand Down Expand Up @@ -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, {
Expand Down
8 changes: 8 additions & 0 deletions src/cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
6 changes: 6 additions & 0 deletions src/nlp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down