Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Scheduling

Commands can run on recurring cron schedules.

A scheduled command is different from a queued command. Queue a command to run it once, as soon as possible. Schedule a command to run it many times, on a fixed interval.

InEngine defines schedules in code, not in a data store. This lets the schedule live alongside the command code in version control.

Scheduling a Command

Use the Schedule struct to register commands with cron expressions.

#![allow(unused)]
fn main() {
use inengine_core::scheduling::schedule::Schedule;

let mut schedule = Schedule::new();

let job = schedule
    .command(MyCommand { /* ... */ })
    .every_five_minutes()?;
schedule.add(job);
}

Use a custom cron expression:

#![allow(unused)]
fn main() {
let job = schedule
    .command(MyCommand { /* ... */ })
    .cron("15 * * * * *")?;
schedule.add(job);
}

Convenience Methods

MethodCron Expression
every_second* * * * * *
every_minute0 * * * * *
every_five_minutes0 */5 * * * *
every_ten_minutes0 */10 * * * *
every_fifteen_minutes0 */15 * * * *
every_thirty_minutes0 */30 * * * *
hourly0 0 * * * *
hourly_at(27)0 27 * * * *
daily0 0 0 * * *
daily_at(22, 30)0 30 22 * * *

Scheduling a Chain

Schedule a group of commands to run as a chain. The chain stops if one command fails.

#![allow(unused)]
fn main() {
let cmds: Vec<Box<dyn Command>> = vec![
    Box::new(TransferFile { path: path1 }),
    Box::new(TransferFile { path: path2 }),
    Box::new(TransferFile { path: path3 }),
];

let job = schedule.commands(cmds).daily()?;
schedule.add(job);
}

Lifecycle Methods

Scheduled jobs support lifecycle hooks.

Ping a URL before or after the command runs:

#![allow(unused)]
fn main() {
let job = schedule
    .command(MyCommand { /* ... */ })
    .every_five_minutes()?
    .ping_before("https://example.com/start")
    .ping_after("https://example.com/done");
schedule.add(job);
}

Write command output to a file:

#![allow(unused)]
fn main() {
let job = schedule
    .command(MyCommand { /* ... */ })
    .hourly()?
    .write_output_to("/var/log/my-command.log");
schedule.add(job);
}

Append command output to a file:

#![allow(unused)]
fn main() {
let job = schedule
    .command(MyCommand { /* ... */ })
    .hourly()?
    .append_output_to("/var/log/my-command.log");
schedule.add(job);
}

Email command output:

#![allow(unused)]
fn main() {
let job = schedule
    .command(MyCommand { /* ... */ })
    .daily()?
    .email_output_to("ops@example.com");
schedule.add(job);
}

The output is written, appended, and mailed when the command succeeds and when it fails. The mail subject is Command completed: <name> or Command failed: <name>. A failure mail ends with the error and each of its causes. Nothing is written or mailed for a command that the server stopped, a command that ignored its deadline, or a command that panicked. Nothing is written or mailed for a successful run whose ping_after request fails, because that run fails.

A ping fails when the server answers with an error status, and the job fails with it.

Set a timeout:

#![allow(unused)]
fn main() {
use std::time::Duration;

let job = schedule
    .command(MyCommand { /* ... */ })
    .hourly()?
    .timeout(Duration::from_secs(300));
schedule.add(job);
}

Run custom logic before or after. The hooks run on the server’s async threads, so they must not block:

#![allow(unused)]
fn main() {
let job = schedule
    .command(MyCommand { /* ... */ })
    .every_five_minutes()?
    .before_run(|| println!("starting"))
    .after_run(|| println!("finished"));
schedule.add(job);
}

Running a Schedule

Give the schedule to the server:

#![allow(unused)]
fn main() {
use std::sync::Arc;

use inengine_core::queue::CommandRegistry;
use inengine_core::server::host::Server;

let server = Server::new(settings, Arc::new(CommandRegistry::new()), schedule);
server.run(cancel).await;
}

A plugin can also add schedules. See Plugins.

Viewing Scheduled Commands

List the plugin schedules and their next fire time:

inengine schedule list

Running the Scheduler

The server runs the plugin schedules:

inengine -s

A schedule built in Rust code runs only in a server that your program starts with Server::new.