use super::expression::CronExpression;
use crate::error::FrameworkError;
use async_trait::async_trait;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub type BoxedTask = Arc<dyn TaskHandler + Send + Sync>;
pub type TaskResult = Result<(), FrameworkError>;
pub type BoxedFuture<'a> = Pin<Box<dyn Future<Output = TaskResult> + Send + 'a>>;
#[async_trait]
pub trait TaskHandler: Send + Sync {
async fn handle(&self) -> TaskResult;
}
#[async_trait]
pub trait Task: Send + Sync {
async fn handle(&self) -> TaskResult;
}
#[async_trait]
impl<T: Task> TaskHandler for T {
async fn handle(&self) -> TaskResult {
Task::handle(self).await
}
}
pub struct TaskEntry {
pub name: String,
pub expression: CronExpression,
pub task: BoxedTask,
pub description: Option<String>,
pub without_overlapping: bool,
pub run_in_background: bool,
}
impl TaskEntry {
pub fn is_due(&self) -> bool {
self.expression.is_due()
}
pub async fn run(&self) -> TaskResult {
self.task.handle().await
}
pub fn schedule_description(&self) -> &str {
self.expression.expression()
}
}
pub(crate) struct ClosureTask<F>
where
F: Fn() -> BoxedFuture<'static> + Send + Sync,
{
pub(crate) handler: F,
}
#[async_trait]
impl<F> TaskHandler for ClosureTask<F>
where
F: Fn() -> BoxedFuture<'static> + Send + Sync,
{
async fn handle(&self) -> TaskResult {
(self.handler)().await
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestTask;
#[async_trait]
impl Task for TestTask {
async fn handle(&self) -> TaskResult {
Ok(())
}
}
#[tokio::test]
async fn test_task_trait() {
let task = TestTask;
let result: TaskResult = Task::handle(&task).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_task_entry() {
let task = TestTask;
let entry = TaskEntry {
name: "test-task".to_string(),
expression: CronExpression::every_minute(),
task: Arc::new(task),
description: Some("A test task".to_string()),
without_overlapping: false,
run_in_background: false,
};
assert_eq!(entry.name, "test-task");
assert_eq!(entry.schedule_description(), "* * * * *");
let result = entry.run().await;
assert!(result.is_ok());
}
}