Skip to content

Commit

Permalink
feat(schedule): add support to scheduled tasks with --cron
Browse files Browse the repository at this point in the history
  • Loading branch information
Joxit committed Oct 9, 2023
1 parent 979d8ef commit 9b01335
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ json = "^0.12"
hostname = "^0.3"
regex = "^1.3"
chrono = "^0.4"
cron = "0.12"
28 changes: 23 additions & 5 deletions src/commands/exec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::config::Config;
use crate::utils::traits::CommandConfig;
use crate::utils::traits::{CommandConfig, WaitSchedule};
use chrono::Local;
use cron::Schedule;
use libc::{fork, signal};
use libc::{SIGHUP, SIG_IGN};
use std::fs;
Expand All @@ -9,7 +11,9 @@ use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Exec {
/// Configuration path (YAML)
/// Configuration path (YAML).
/// Will use config file located `~/.runtasktic.yml` or `~/.runtasktic.yaml` by default.
/// If you want no config file execusion, use `--config -`
#[structopt(long = "config", short = "c")]
config: Option<PathBuf>,
/// Run a single task from the configuration file.
Expand All @@ -18,6 +22,9 @@ pub struct Exec {
/// Exec the command in background
#[structopt(long = "background", short = "b")]
background: bool,
/// Schedule your tasks using cron expression.
#[structopt(long = "cron")]
cron: Option<Schedule>,
/// Command to execute
#[structopt()]
command: Vec<String>,
Expand All @@ -31,6 +38,7 @@ impl Exec {
return;
}
}
let timezone = Local::now().timezone();

if self.command.is_empty() && self.task.is_none() {
let clap = crate::Runtasktic::clap();
Expand All @@ -46,9 +54,19 @@ impl Exec {
unsafe { signal(SIGHUP, SIG_IGN) };
}

if let Err(e) = self.run() {
eprintln!("{}", e);
exit(1);
loop {
self.cron.wait(timezone);

if let Err(e) = self.run() {
eprintln!("{}", e);
if self.cron.is_none() {
exit(1);
}
}

if self.cron.is_none() {
break;
}
}
}

Expand Down
25 changes: 19 additions & 6 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::config::{Config, OnFailure};
use crate::fst::*;
use crate::utils::traits::CommandConfig;
use crate::utils::traits::{CommandConfig, WaitSchedule};
use chrono::Local;
use cron::Schedule;
use libc::{fork, signal};
use libc::{SIGHUP, SIG_IGN};
use std::fs;
Expand All @@ -21,6 +23,9 @@ pub struct Run {
/// Run the task in background
#[structopt(long = "background", short = "b")]
background: bool,
/// Schedule your tasks using cron expression.
#[structopt(long = "cron")]
cron: Option<Schedule>,
}

impl Run {
Expand All @@ -31,6 +36,7 @@ impl Run {
exit(1);
}
}
let timezone = Local::now().timezone();

if self.config.is_empty() {
let clap = crate::Runtasktic::clap();
Expand All @@ -46,11 +52,18 @@ impl Run {
unsafe { signal(SIGHUP, SIG_IGN) };
}

for (i, config) in self.config.iter().enumerate() {
let starts = if i == 0 { self.starts.clone() } else { vec![] };
if let Err(e) = self.run(&config.as_path(), &starts) {
eprintln!("{}", e);
exit(1);
loop {
self.cron.wait(timezone);

for (i, config) in self.config.iter().enumerate() {
let starts = if i == 0 { self.starts.clone() } else { vec![] };
if let Err(e) = self.run(&config.as_path(), &starts) {
eprintln!("{}", e);
exit(1);
}
}
if self.cron.is_none() {
break;
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/utils/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub(crate) use command_config::CommandConfig;
pub(crate) use wait_schedule::WaitSchedule;

mod command_config;
mod wait_schedule;
29 changes: 29 additions & 0 deletions src/utils/traits/wait_schedule.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use chrono::Local;
use cron::Schedule;

pub trait WaitSchedule<T> {
fn wait(&self, timezone: T);
}

impl WaitSchedule<Local> for Option<Schedule> {
fn wait(&self, timezone: Local) {
if let Some(cron) = self {
cron.wait(timezone);
}
}
}

impl WaitSchedule<Local> for Schedule {
fn wait(&self, timezone: Local) {
let date = self
.upcoming(timezone)
.next()
.expect("Cannot get upcoming cron date");

std::thread::sleep(
(date - Local::now())
.to_std()
.expect("Cannot transform Duration"),
);
}
}

0 comments on commit 9b01335

Please sign in to comment.