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
27 changes: 15 additions & 12 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,15 @@ export const cli = new Command().name("cronx")
},
})
.option(
`--suppress-stdio`,
`Whether or not to suppress your executable's "stdout" and "stderr"`,
`--suppress-stdout`,
`Whether or not to suppress your executable's "stdout"`,
{
default: false,
},
)
.option(
`--suppress-stderr`,
`Whether or not to suppress your executable's "stderr"`,
{
default: false,
},
Expand All @@ -76,7 +83,8 @@ export const cli = new Command().name("cronx")
const {
tab,
offset,
suppressStdio,
suppressStdout,
suppressStderr,
} = options;

if (options.label) {
Expand Down Expand Up @@ -183,21 +191,16 @@ export const cli = new Command().name("cronx")
const jobLogger = new JobLogger(label);

if (options.run) {
cconsole.debug();
cconsole.debug(
`Running job: ${job} ${
suppressStdio ? "and suppressing output to" : "writing output to"
} stdout and stderr`,
);
cconsole.debug();
await runExecutable(job, {
suppressStdio,
suppressStdout,
suppressStderr,
jobLogger,
});
}

scheduleCronWithExecutable(job, {
suppressStdio,
suppressStdout,
suppressStderr,
jobLogger,
label,
cronxExpression: cronExpression!,
Expand Down
44 changes: 27 additions & 17 deletions src/cronx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@

import { cconsole } from "cconsole";

import { convertCronxExpressionToDenoCronExpression } from "./cron.ts";
import {
convertCronxExpressionToDenoCronExpression,
getLocalUTCOffset,
} from "./cron.ts";

import { runExecutable } from "src/executables.ts";

import type { JobLogger } from "./JobLogger.ts";
import type { Logger } from "./JobLogger.ts";
import type { LogLevel } from "@polyseam/cconsole";

/**
* Validates a job label accepting only alphanumeric characters, whitespace, hyphens, and underscores.
Expand All @@ -31,16 +35,20 @@ export type ScheduleExecutableOptions = {
cronxExpression: string;
label?: string;
offset?: number; // timezone utc offset in hours
suppressStdio?: boolean;
jobLogger?: JobLogger;
suppressStdout?: boolean;
suppressStderr?: boolean;
jobLogger?: Logger;
logLevel?: LogLevel;
};

/**
* Schedules a cron job to execute a command-line executable.
*
* @param job - The command-line executable to run
* @param opt - Configuration options for the scheduled job
* @param opt.suppressStdio - Whether to suppress standard input/output
* @param opt.logLevel - The log level for cronx
* @param opt.suppressStdout - Whether to suppress stdout
* @param opt.suppressStderr - Whether to suppress stderr
* @param opt.jobLogger - Optional custom logger function for job execution
* @param opt.cronxExpression - The cron expression defining the schedule
* @param opt.offset - Optional timezone offset in hours (defaults to local timezone offset)
Expand All @@ -58,8 +66,12 @@ export function scheduleCronWithExecutable(
job: string,
opt: ScheduleExecutableOptions,
) {
const { suppressStdio, jobLogger, cronxExpression } = opt;
const offset = opt.offset ?? new Date().getTimezoneOffset() / -60;
const { suppressStdout, suppressStderr, jobLogger, cronxExpression } = opt;

const offset = opt?.offset ?? getLocalUTCOffset();
const logLevel = opt?.logLevel ?? "INFO";

cconsole.setLogLevel(logLevel);

let label = job;

Expand All @@ -82,21 +94,15 @@ export function scheduleCronWithExecutable(
);

Deno.cron(label, denoCronExpression, async () => {
cconsole.debug();
cconsole.debug(
`Running job: ${job} ${
suppressStdio ? "and suppressing output to" : "writing output to"
} stdout and stderr`,
);
cconsole.debug();
await runExecutable(job, { suppressStdio, jobLogger });
await runExecutable(job, { suppressStdout, suppressStderr, jobLogger });
});
}

export type ScheduleFunctionOptions = {
cronxExpression: string;
label?: string;
offset?: number;
logLevel?: LogLevel;
};

/**
Expand Down Expand Up @@ -124,18 +130,22 @@ export function scheduleCronWithFunction(
) {
const { cronxExpression } = opt;

const offset = opt.offset ?? new Date().getTimezoneOffset() / -60;
const offset = opt.offset ?? getLocalUTCOffset();

const label = opt.label ?? jobFn.name;

const logLevel = opt.logLevel ?? "INFO";

cconsole.setLogLevel(logLevel);

const denoCronExpression = convertCronxExpressionToDenoCronExpression(
cronxExpression,
offset,
);

Deno.cron(label, denoCronExpression, async () => {
cconsole.debug();
cconsole.debug("Running job function: " + label);
cconsole.debug("Running function job: " + label);
cconsole.debug();
await jobFn();
});
Expand Down
53 changes: 39 additions & 14 deletions src/executables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
*/

import { JobLogger, type Logger } from "./JobLogger.ts";
import { cconsole } from "cconsole";

type RunExecutableOptions = {
suppressStdio?: boolean;
suppressStdout?: boolean;
suppressStderr?: boolean;
jobLogger?: Logger;
};

Expand All @@ -26,7 +28,7 @@ type RunExecutableOptions = {
* @example
* ```ts
* await runExecutable("echo hello", {
* suppressStdio: false,
* suppressStderr: true,
* jobLogger: console
* });
* ```
Expand All @@ -35,11 +37,15 @@ export async function runExecutable(
job: string,
options: RunExecutableOptions,
) {
const suppressStdio = options?.suppressStdio || false;
const suppressStdout = options?.suppressStdout || false;
const suppressStderr = options?.suppressStderr || false;

printDebugJobStatus({ suppressStderr, suppressStdout, job });

const jobLogger = options?.jobLogger || new JobLogger();

const stdout = suppressStdio ? "null" : "piped";
const stderr = suppressStdio ? "null" : "piped";
const stdout = suppressStdout ? "null" : "piped";
const stderr = suppressStderr ? "null" : "piped";

const [c, ...args] = job.split(" ");

Expand All @@ -51,15 +57,34 @@ export async function runExecutable(

const output = await cmd.output();
const d = new TextDecoder();
if (!suppressStdio) {
const stdoutTxt = d.decode(output.stdout);
const stderrTxt = d.decode(output.stderr);

if (stdoutTxt) {
jobLogger.log(stdoutTxt);
}
if (stderrTxt) {
jobLogger.error(stderrTxt);
}
if (!suppressStdout) {
jobLogger.log(d.decode(output.stdout));
}

// note: stderr is not always an error
// unix philosophy says to use stderr for any diagnostic logging
if (!suppressStderr) {
jobLogger.error(d.decode(output.stderr));
}
}

function printDebugJobStatus(
{ suppressStdout, suppressStderr, job }: {
suppressStdout: boolean;
suppressStderr: boolean;
job: string;
},
) {
cconsole.debug();
cconsole.debug(
`Running job: ${job} with`,
);
cconsole.debug(
`stdout: ${suppressStdout ? "suppressed" : "reflected"}`,
);
cconsole.debug(
`stderr: ${suppressStderr ? "suppressed" : "reflected"}`,
);
cconsole.debug();
}