1use std::sync::Arc;
7use async_trait::async_trait;
8use alun_core::{Plugin, Result as CoreResult};
9use tokio::task::JoinHandle;
10use tracing::{info, error};
11
12use crate::storage::TaskStorage;
13use crate::HandlerRegistry;
14use crate::TaskWorker;
15use crate::RetryScanner;
16use crate::TaskMetrics;
17use crate::TaskWorkerConfig;
18
19pub struct TaskPlugin {
36 config: TaskWorkerConfig,
38 storage: Arc<dyn TaskStorage>,
40 registry: HandlerRegistry,
42 handles: parking_lot::Mutex<Vec<JoinHandle<()>>>,
44 running: Arc<std::sync::atomic::AtomicBool>,
46 metrics: Arc<TaskMetrics>,
48 topics: Vec<String>,
50}
51
52impl TaskPlugin {
53 pub fn new(
59 config: TaskWorkerConfig,
60 storage: Arc<dyn TaskStorage>,
61 registry: HandlerRegistry,
62 ) -> Result<Self, String> {
63 let mut topics: Vec<String> = registry
64 .task_types()
65 .iter()
66 .filter_map(|tt| registry.get_config(*tt).map(|c| c.topic.clone()))
67 .collect();
68 topics.sort_unstable();
69 topics.dedup();
70
71 let metrics = Arc::new(TaskMetrics::new());
72
73 Ok(Self {
74 config,
75 storage,
76 registry,
77 handles: parking_lot::Mutex::new(Vec::new()),
78 running: Arc::new(std::sync::atomic::AtomicBool::new(true)),
79 metrics,
80 topics,
81 })
82 }
83
84 pub fn metrics(&self) -> Arc<TaskMetrics> {
86 Arc::clone(&self.metrics)
87 }
88
89 pub fn topics(&self) -> &[String] {
91 &self.topics
92 }
93
94 fn signal_stop(&self) {
95 self.running.store(false, std::sync::atomic::Ordering::Relaxed);
96 }
97
98 async fn wait_for_tasks(&self) {
99 let handles: Vec<JoinHandle<()>> = {
100 let mut guard = self.handles.lock();
101 std::mem::take(&mut *guard)
102 };
103 for handle in handles {
104 let _ = handle.await;
105 }
106 }
107}
108
109#[async_trait]
110impl Plugin for TaskPlugin {
111 fn name(&self) -> &str {
112 "task"
113 }
114
115 fn depends_on(&self) -> &[&str] {
116 &[]
117 }
118
119 async fn start(&self) -> CoreResult<()> {
121 self.running.store(true, std::sync::atomic::Ordering::Relaxed);
122
123 let topics = self.topics.clone();
124 let running = Arc::clone(&self.running);
125 let metrics = Arc::clone(&self.metrics);
126
127 let worker = {
128 let w_config = self.config.clone();
129 let w_storage = Arc::clone(&self.storage);
130 let w_registry = self.registry.clone();
131 let w_metrics = Arc::clone(&metrics);
132 let w_running = Arc::clone(&running);
133 let w_topics = topics.clone();
134
135 tokio::spawn(async move {
136 let w_config_clone = w_config.clone();
137 let w_storage_clone = Arc::clone(&w_storage);
138 let w_registry_clone = w_registry.clone();
139 let worker = match TaskWorker::new(w_config_clone, w_storage_clone, w_registry_clone, w_metrics, &w_topics) {
140 Ok(w) => Arc::new(w),
141 Err(e) => {
142 error!("TaskWorker 创建失败: {}", e);
143 return;
144 }
145 };
146
147 let worker_ref = Arc::clone(&worker);
148 let run_fut = worker_ref.run();
149
150 tokio::select! {
151 result = run_fut => {
152 if let Err(e) = result {
153 error!("TaskWorker 运行异常: {}", e);
154 }
155 }
156 _ = async {
157 while w_running.load(std::sync::atomic::Ordering::Relaxed) {
158 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
159 }
160 } => {
161 worker_ref.stop();
162 }
163 }
164 })
165 };
166
167 let scanner = {
168 let s_brokers = self.config.brokers.clone();
169 let s_storage = Arc::clone(&self.storage);
170 let s_registry = self.registry.clone();
171 let s_interval = self.config.scan_interval_secs;
172 let s_batch = self.config.max_batch_size;
173 let s_running = Arc::clone(&running);
174
175 tokio::spawn(async move {
176 let scanner = match RetryScanner::new(
177 &s_brokers, s_storage, s_registry, s_interval, s_batch,
178 ) {
179 Ok(s) => Arc::new(s),
180 Err(e) => {
181 error!("RetryScanner 创建失败: {}", e);
182 return;
183 }
184 };
185
186 let scanner_ref = Arc::clone(&scanner);
187
188 tokio::select! {
189 _ = scanner_ref.run() => {}
190 _ = async {
191 while s_running.load(std::sync::atomic::Ordering::Relaxed) {
192 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
193 }
194 } => {
195 scanner_ref.stop();
196 }
197 }
198 })
199 };
200
201 self.handles.lock().push(worker);
202 self.handles.lock().push(scanner);
203
204 info!(
205 "TaskPlugin 启动: topics={:?}, brokers={}, group={}",
206 self.topics, self.config.brokers, self.config.group_id
207 );
208 Ok(())
209 }
210
211 async fn stop(&self) -> CoreResult<()> {
213 info!("TaskPlugin 收到停止信号");
214 self.signal_stop();
215 self.wait_for_tasks().await;
216 info!("TaskPlugin 已停止");
217 Ok(())
218 }
219}