use crate::{
task::{Handler, Task},
Schedule,
};
use ayun_core::{
app,
traits::{ApplicationTrait, ServiceTrait},
};
use ayun_runtime::Runtime;
impl ServiceTrait for Schedule {
type Item = Task;
fn new() -> Self {
Self::default()
}
fn register(mut self, item: Self::Item) -> Self {
self.tasks.push(item);
self
}
fn init<A: ApplicationTrait>() -> Self {
(&A::with_schedule() as &dyn std::any::Any)
.downcast_ref::<Self>()
.cloned()
.unwrap_or(Self::default())
}
fn run(self) -> Result<(), crate::Error> {
let sync_tasks = self
.tasks()
.iter()
.filter(|task| !task.handler().is_async())
.cloned()
.collect::<Vec<_>>();
if !sync_tasks.is_empty() {
std::thread::spawn(|| foreground(sync_tasks));
}
let async_tasks = self
.tasks()
.iter()
.filter(|task| task.handler().is_async())
.cloned()
.collect::<Vec<_>>();
if !async_tasks.is_empty() {
let runtime = app().resolve::<Runtime>()?;
runtime.spawn(background(async_tasks));
}
Ok(())
}
}
fn foreground(mut tasks: Vec<Task>) {
loop {
for task in &mut tasks {
if !task.available() {
continue;
}
if let Handler::Sync(handler) = task.handler() {
handler();
task.set_last_tick(chrono::Local::now());
}
}
std::thread::sleep(delay(&tasks));
}
}
async fn background(mut tasks: Vec<Task>) {
loop {
for task in &mut tasks {
if !task.available() {
continue;
}
if let Handler::Async(handler) = task.handler() {
handler().await;
task.set_last_tick(chrono::Local::now());
}
}
tokio::time::sleep(delay(&tasks)).await;
}
}
fn delay(tasks: &[Task]) -> std::time::Duration {
tasks
.iter()
.map(|task| task.delay())
.min()
.unwrap_or(std::time::Duration::from_millis(500))
}