diff --git a/Cargo.lock b/Cargo.lock index 70b022e..f0564d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1093,6 +1093,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inventory" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" + [[package]] name = "ipnet" version = "2.9.0" @@ -1179,6 +1185,7 @@ dependencies = [ "http-body-util", "hyper", "i18n", + "inventory", "jsonwebtoken", "lazy_static", "macro", diff --git a/Cargo.toml b/Cargo.toml index 33f2aad..577200b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,4 +60,5 @@ strum_macros = "0.26.3" hex = "0.4.3" redis = "0.27.4" deadpool-redis = "0.18.0" -chrono-tz = "0.10.0" \ No newline at end of file +chrono-tz = "0.10.0" +inventory = "0.3.15" \ No newline at end of file diff --git a/library/Cargo.toml b/library/Cargo.toml index 2337d57..c558c61 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -39,6 +39,7 @@ hex = { workspace = true } redis = { workspace = true, features = ["tokio-comp", "json"] } deadpool-redis = { workspace = true } chrono-tz = { workspace = true } +inventory = { workspace = true } domain = { path = "../domain" } i18n = { path = "../i18n" } diff --git a/library/src/task.rs b/library/src/task.rs index ca3a7a9..23e4b4b 100644 --- a/library/src/task.rs +++ b/library/src/task.rs @@ -3,8 +3,14 @@ use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; use chrono_tz::Tz; use tokio_cron_scheduler::{Job, JobScheduler, JobSchedulerError}; +pub use inventory::submit; + type TaskFun = dyn Fn() -> Pin + Send>> + Send + Sync; +pub trait TaskMethod: Send + Sync + 'static { + fn ge_task(&self) -> Task; +} + pub struct Task{ pub job: Arc, pub cron: Option, @@ -13,14 +19,15 @@ pub struct Task{ } /// 启动定时任务 -pub async fn start(tasks: Vec) { +pub async fn start() { + let tasks = get_task_methods(); match schedule(tasks).await { Ok(_) => tracing::info!("定时任务启动成功"), Err(err) => tracing::error!(error = ?err, "定时任务启动失败"), } } -async fn schedule(tasks: Vec) -> Result<(), JobSchedulerError> { +async fn schedule(tasks: Vec>) -> Result<(), JobSchedulerError> { let mut scheduler = JobScheduler::new().await?; scheduler.init().await?; @@ -61,3 +68,22 @@ async fn schedule(tasks: Vec) -> Result<(), JobSchedulerError> { scheduler.start().await?; Ok(()) } + +inventory::collect!(&'static dyn TaskMethod); + +#[macro_export] +macro_rules! submit_task { + ($ty:ident) => { + ::library::task::submit! { + &$ty as &dyn ::library::task::TaskMethod + } + }; +} + +fn get_task_methods() -> Vec> { + let mut result = Vec::>::new(); + for method in inventory::iter::<&dyn TaskMethod> { + result.push(Arc::new(method.ge_task())); + } + result +} diff --git a/macro/src/task.rs b/macro/src/task.rs index 9fbb32f..8b8633e 100644 --- a/macro/src/task.rs +++ b/macro/src/task.rs @@ -77,12 +77,12 @@ pub fn gen_task(attr: TokenStream, item: TokenStream) -> TokenStream { let TaskArgs{ cron, interval, time_zone } = parse_macro_input!(attr as TaskArgs); // 将 method 转换为小写并生成标识符 - let vis = func.vis.clone(); + // let vis = func.vis.clone(); let ident = func.sig.ident.clone(); let result = quote!{ let mut _result = library::task::Task { - job: std::sync::Arc::new(|| Box::pin(#ident ())), + job: std::sync::Arc::new(|| Box::pin(#ident::#ident ())), cron: None, interval: None, time_zone: None, @@ -100,11 +100,18 @@ pub fn gen_task(attr: TokenStream, item: TokenStream) -> TokenStream { }; let generated = quote! { - #vis fn #ident () -> library::task::Task { + #[allow(non_camel_case_types)] + struct #ident; + impl #ident { #func - - #result } + impl library::task::TaskMethod for #ident { + fn ge_task(&self) -> library::task::Task { + #result + } + } + + ::library::submit_task!(#ident); }; TokenStream::from(generated) diff --git a/server/src/lib.rs b/server/src/lib.rs index 5d58218..2600a88 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,6 +1,5 @@ use axum::{body::Body, extract::Request, http, routing::get, Router}; use library::{config, task}; -use tasks::get_tasks; use tower::ServiceBuilder; use tower_http::trace::TraceLayer; @@ -15,7 +14,7 @@ pub async fn serve() { tracing::info!("服务监听地址: {}", addr); // 启动任务 - task::start(get_tasks()).await; + task::start().await; // 启动应用服务 axum::serve(listener, init()).await.unwrap(); } diff --git a/server/src/tasks/mod.rs b/server/src/tasks/mod.rs index 49a9f42..544d4ae 100644 --- a/server/src/tasks/mod.rs +++ b/server/src/tasks/mod.rs @@ -1,9 +1 @@ -use library::task::Task; - -pub mod google_tasks; - -/// 定时任务维护器 -pub fn get_tasks() -> Vec { - vec![google_tasks::xxx_task(), google_tasks::xxx_task2()] -} - +pub mod google_tasks; \ No newline at end of file