Scripts

A cron's entry point is cronhoster-cron-handler.js, an ordinary Node script at the top of the cron directory. When a run matches the current second, the runner starts the handler as a fresh Node process, with the cron directory as its working directory, and passes the matched time on the command line. There is no framework to import, no ctx object, and no required module.exports. The handler is just a script that reads process.argv and does its work.

Command-line arguments

The runner spawns the handler with the cron name, the name of the run that matched, and the six matched time fields, in this order:

node cronhoster-cron-handler.js <cron> <run> <year> <month> <day> <hour> <minute> <second>
How the runner invokes a handler.
PositionNameMeaning
argv[2]cronThe cron name, which is the directory name.
argv[3]runThe name of the run that matched.
argv[4]yearMatched UTC year.
argv[5]monthMatched UTC month, 1 to 12.
argv[6]dayMatched UTC day of month, 1 to 31.
argv[7]hourMatched UTC hour, 0 to 23.
argv[8]minuteMatched UTC minute, 0 to 59.
argv[9]secondMatched UTC second, 0 to 59.

An example handler

A handler destructures process.argv.slice(2) and does its work. Whatever it writes to stdout and stderr is captured for the Cron Logs tool:

const [cron, run, year, month, day, hour, minute, second] = process.argv.slice(2);
console.log(`${cron}/${run} fired at ${year}-${month}-${day} ${hour}:${minute}:${second} UTC`);
A handler reads the matched time and logs it.

Success and failure

A run succeeds when its process exits with code 0. A run fails when the process exits with any non-zero code, or when the handler throws and the process exits non-zero as a result. Either way the run is recorded with its start time, duration, exit code, and the captured stdout and stderr.

A failure never retries. It never blocks the next run beyond the cron's concurrency ceiling: the next matching time starts a fresh process as usual, up to cronhoster-cron-setting-maxConcurrent handlers running at once. Read the records in the Cron Logs tool to see what happened.

Bundled modules and resolution

Only cronhoster-cron-handler.js is run. Anything else inside the cron directory is a module the handler imports, uploaded as part of the cron, and never run on its own. Because the process starts with the cron directory as its working directory, require and import resolve from there: a relative path resolves against the importing file, and a node_modules folder inside the cron is honoured. A cron carries its own copy of everything it needs, so it is self-contained and nothing resolves across cron boundaries.

const { format } = require('./format');
const { send } = require('./mailer');

async function main() {
  const [cron, run] = process.argv.slice(2);
  await send(format(await gather()));
}

main();
A handler importing modules bundled beside it.

See the Files reference for which paths are crons, which are the modules inside them, and which are ignored. The schedule that decides when a handler runs lives in the cron's settings, and the day-to-day workflow is in Usage.