1use crate::lifecycle::config::{SchedulingStrategy, TaskPriority, TaskType};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10use std::time::{Duration, Instant};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct BackgroundTask {
15 pub task_id: String,
17 pub task_type: TaskType,
19 pub priority: TaskPriority,
21 pub scheduling_strategy: SchedulingStrategy,
23 pub resource_requirements: ResourceRequirements,
25 pub execution_constraints: ExecutionConstraints,
27 pub metadata: TaskMetadata,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct ResourceRequirements {
34 pub min_cpu_percent: u8,
36 pub max_cpu_percent: u8,
38 pub min_memory_mb: usize,
40 pub max_memory_mb: usize,
42 pub network_bandwidth_mbps: Option<f32>,
44 pub requires_gpu: bool,
46 pub storage_io_mbps: Option<f32>,
48 pub estimated_execution_time_seconds: u64,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ExecutionConstraints {
55 pub max_execution_time_seconds: u64,
57 pub retry_attempts: u32,
59 pub retry_delay_seconds: u64,
61 pub requires_network: bool,
63 pub min_battery_percent: u8,
65 pub max_thermal_level: crate::lifecycle::config::ThermalLevel,
67 pub background_eligible: bool,
69 pub requires_user_presence: bool,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct TaskMetadata {
76 pub name: String,
78 pub description: String,
80 pub created_timestamp: u64,
82 pub scheduled_timestamp: Option<u64>,
84 pub last_execution_timestamp: Option<u64>,
86 pub execution_count: usize,
88 pub success_count: usize,
90 pub failure_count: usize,
92 pub tags: Vec<String>,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
98pub enum TaskStatus {
99 Pending,
101 Scheduled,
103 Running,
105 Paused,
107 Completed,
109 Failed,
111 Cancelled,
113 TimedOut,
115 Deferred,
117 WaitingForResources,
119 WaitingForConditions,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct TaskResult {
126 pub task_id: String,
128 pub status: TaskStatus,
130 pub start_timestamp: u64,
132 pub end_timestamp: Option<u64>,
134 pub execution_time_seconds: f64,
136 pub resource_usage: TaskResourceUsage,
138 pub output_data: Option<Vec<u8>>,
140 pub error_info: Option<TaskError>,
142 pub performance_metrics: TaskPerformanceMetrics,
144 pub quality_metrics: Option<TaskQualityMetrics>,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct TaskResourceUsage {
151 pub peak_cpu_percent: f32,
153 pub avg_cpu_percent: f32,
155 pub peak_memory_mb: usize,
157 pub avg_memory_mb: usize,
159 pub network_data_mb: f32,
161 pub storage_io_mb: f32,
163 pub gpu_usage_percent: Option<f32>,
165 pub battery_consumption_mah: f32,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct TaskError {
172 pub error_code: u32,
174 pub error_message: String,
176 pub error_category: TaskErrorCategory,
178 pub recoverable: bool,
180 pub retry_recommended: bool,
182 pub details: HashMap<String, String>,
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
188pub enum TaskErrorCategory {
189 ResourceUnavailable,
190 NetworkError,
191 AuthenticationError,
192 PermissionError,
193 DataError,
194 SystemError,
195 TimeoutError,
196 UserCancellation,
197 InternalError,
198 ConfigurationError,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct TaskPerformanceMetrics {
204 pub throughput_ops_per_second: f32,
206 pub latency_percentiles: LatencyPercentiles,
208 pub error_rate_percent: f32,
210 pub resource_efficiency_score: f32,
212 pub completion_rate_percent: f32,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct LatencyPercentiles {
219 pub p50_ms: f32,
221 pub p90_ms: f32,
223 pub p95_ms: f32,
225 pub p99_ms: f32,
227 pub max_ms: f32,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct TaskQualityMetrics {
234 pub accuracy_score: f32,
236 pub precision_score: f32,
238 pub recall_score: f32,
240 pub f1_score: f32,
242 pub model_drift_score: Option<f32>,
244 pub data_quality_score: Option<f32>,
246}
247
248pub struct BackgroundCoordinator {
250 task_queue: Arc<std::sync::Mutex<Vec<BackgroundTask>>>,
251 running_tasks: Arc<std::sync::Mutex<HashMap<String, TaskExecutionContext>>>,
252 completed_tasks: Arc<std::sync::Mutex<Vec<TaskResult>>>,
253 execution_context: BackgroundExecutionContext,
254 task_registry: TaskRegistry,
255 max_concurrent_tasks: usize,
256}
257
258pub struct TaskExecutionContext {
260 pub task: BackgroundTask,
261 pub start_time: Instant,
262 pub allocated_resources: AllocatedResources,
263 pub status: TaskStatus,
264 pub progress: f32, }
266
267#[derive(Debug, Clone)]
269pub struct AllocatedResources {
270 pub cpu_percent: u8,
271 pub memory_mb: usize,
272 pub network_mbps: Option<f32>,
273 pub gpu_allocation: Option<f32>,
274 pub storage_io_mbps: Option<f32>,
275}
276
277pub struct BackgroundExecutionContext {
279 pub available_cpu_percent: u8,
280 pub available_memory_mb: usize,
281 pub available_network_mbps: f32,
282 pub battery_level_percent: u8,
283 pub thermal_level: crate::lifecycle::config::ThermalLevel,
284 pub network_connected: bool,
285 pub user_present: bool,
286 pub system_load: f32,
287}
288
289pub struct TaskRegistry {
291 registered_tasks: HashMap<TaskType, Vec<BackgroundTask>>,
292 task_templates: HashMap<TaskType, BackgroundTask>,
293}
294
295impl BackgroundCoordinator {
296 pub fn new(max_concurrent_tasks: usize) -> Self {
298 Self {
299 task_queue: Arc::new(std::sync::Mutex::new(Vec::new())),
300 running_tasks: Arc::new(std::sync::Mutex::new(HashMap::new())),
301 completed_tasks: Arc::new(std::sync::Mutex::new(Vec::new())),
302 execution_context: BackgroundExecutionContext::default(),
303 task_registry: TaskRegistry::new(),
304 max_concurrent_tasks,
305 }
306 }
307
308 pub fn schedule_task(&self, task: BackgroundTask) -> Result<(), Box<dyn std::error::Error>> {
310 let mut queue = self.task_queue.lock().expect("Operation failed");
311 queue.push(task);
312
313 queue.sort_by(|a, b| {
315 b.priority.cmp(&a.priority).then_with(|| {
316 a.scheduling_strategy
317 .priority_order()
318 .cmp(&b.scheduling_strategy.priority_order())
319 })
320 });
321
322 Ok(())
323 }
324
325 pub fn execute_next_task(&mut self) -> Result<Option<TaskResult>, Box<dyn std::error::Error>> {
327 let running_count = self.running_tasks.lock().expect("Operation failed").len();
328 if running_count >= self.max_concurrent_tasks {
329 return Ok(None);
330 }
331
332 let task = {
333 let mut queue = self.task_queue.lock().expect("Operation failed");
334 if queue.is_empty() {
335 return Ok(None);
336 }
337
338 let mut task_index = None;
340 for (index, task) in queue.iter().enumerate() {
341 if self.can_execute_task(task) {
342 task_index = Some(index);
343 break;
344 }
345 }
346
347 match task_index {
348 Some(index) => queue.remove(index),
349 None => return Ok(None),
350 }
351 };
352
353 let allocated_resources = self.allocate_resources(&task)?;
355 let execution_context = TaskExecutionContext {
356 task: task.clone(),
357 start_time: Instant::now(),
358 allocated_resources,
359 status: TaskStatus::Running,
360 progress: 0.0,
361 };
362
363 self.running_tasks
364 .lock()
365 .expect("Operation failed")
366 .insert(task.task_id.clone(), execution_context);
367
368 let result = self.execute_task_impl(&task)?;
370
371 self.running_tasks.lock().expect("Operation failed").remove(&task.task_id);
373 self.completed_tasks.lock().expect("Operation failed").push(result.clone());
374
375 Ok(Some(result))
376 }
377
378 fn can_execute_task(&self, task: &BackgroundTask) -> bool {
380 if self.execution_context.battery_level_percent
382 < task.execution_constraints.min_battery_percent
383 {
384 return false;
385 }
386
387 if self.execution_context.thermal_level > task.execution_constraints.max_thermal_level {
389 return false;
390 }
391
392 if task.execution_constraints.requires_network && !self.execution_context.network_connected
394 {
395 return false;
396 }
397
398 if task.execution_constraints.requires_user_presence && !self.execution_context.user_present
400 {
401 return false;
402 }
403
404 if task.resource_requirements.min_cpu_percent > self.execution_context.available_cpu_percent
406 {
407 return false;
408 }
409
410 if task.resource_requirements.min_memory_mb > self.execution_context.available_memory_mb {
411 return false;
412 }
413
414 true
415 }
416
417 fn allocate_resources(
419 &self,
420 task: &BackgroundTask,
421 ) -> Result<AllocatedResources, Box<dyn std::error::Error>> {
422 let cpu_percent = task
423 .resource_requirements
424 .min_cpu_percent
425 .min(self.execution_context.available_cpu_percent);
426 let memory_mb = task
427 .resource_requirements
428 .min_memory_mb
429 .min(self.execution_context.available_memory_mb);
430
431 Ok(AllocatedResources {
432 cpu_percent,
433 memory_mb,
434 network_mbps: task.resource_requirements.network_bandwidth_mbps,
435 gpu_allocation: if task.resource_requirements.requires_gpu { Some(50.0) } else { None },
436 storage_io_mbps: task.resource_requirements.storage_io_mbps,
437 })
438 }
439
440 fn execute_task_impl(
442 &self,
443 task: &BackgroundTask,
444 ) -> Result<TaskResult, Box<dyn std::error::Error>> {
445 let start_timestamp = std::time::SystemTime::now()
446 .duration_since(std::time::UNIX_EPOCH)
447 .expect("Operation failed")
448 .as_secs();
449
450 std::thread::sleep(Duration::from_millis(100));
452
453 let end_timestamp = std::time::SystemTime::now()
454 .duration_since(std::time::UNIX_EPOCH)
455 .expect("Operation failed")
456 .as_secs();
457
458 Ok(TaskResult {
459 task_id: task.task_id.clone(),
460 status: TaskStatus::Completed,
461 start_timestamp,
462 end_timestamp: Some(end_timestamp),
463 execution_time_seconds: (end_timestamp - start_timestamp) as f64,
464 resource_usage: TaskResourceUsage {
465 peak_cpu_percent: 25.0,
466 avg_cpu_percent: 20.0,
467 peak_memory_mb: 100,
468 avg_memory_mb: 80,
469 network_data_mb: 1.0,
470 storage_io_mb: 0.5,
471 gpu_usage_percent: None,
472 battery_consumption_mah: 5.0,
473 },
474 output_data: None,
475 error_info: None,
476 performance_metrics: TaskPerformanceMetrics {
477 throughput_ops_per_second: 10.0,
478 latency_percentiles: LatencyPercentiles {
479 p50_ms: 50.0,
480 p90_ms: 80.0,
481 p95_ms: 90.0,
482 p99_ms: 100.0,
483 max_ms: 120.0,
484 },
485 error_rate_percent: 0.0,
486 resource_efficiency_score: 85.0,
487 completion_rate_percent: 100.0,
488 },
489 quality_metrics: None,
490 })
491 }
492
493 pub fn get_running_tasks(&self) -> Vec<(String, TaskStatus, f32)> {
495 self.running_tasks
496 .lock()
497 .expect("Operation failed")
498 .iter()
499 .map(|(id, context)| (id.clone(), context.status, context.progress))
500 .collect()
501 }
502
503 pub fn get_completed_tasks(&self) -> Vec<TaskResult> {
505 self.completed_tasks.lock().expect("Operation failed").clone()
506 }
507}
508
509impl Default for BackgroundExecutionContext {
510 fn default() -> Self {
511 Self {
512 available_cpu_percent: 50,
513 available_memory_mb: 512,
514 available_network_mbps: 10.0,
515 battery_level_percent: 80,
516 thermal_level: crate::lifecycle::config::ThermalLevel::Normal,
517 network_connected: true,
518 user_present: true,
519 system_load: 0.5,
520 }
521 }
522}
523
524impl TaskRegistry {
525 pub fn new() -> Self {
527 Self {
528 registered_tasks: HashMap::new(),
529 task_templates: HashMap::new(),
530 }
531 }
532
533 pub fn register_task_template(&mut self, task_type: TaskType, template: BackgroundTask) {
535 self.task_templates.insert(task_type, template);
536 }
537
538 pub fn create_task_from_template(
540 &self,
541 task_type: TaskType,
542 task_id: String,
543 ) -> Option<BackgroundTask> {
544 self.task_templates.get(&task_type).map(|template| {
545 let mut task = template.clone();
546 task.task_id = task_id;
547 task
548 })
549 }
550
551 pub fn get_tasks_by_type(&self, task_type: TaskType) -> Vec<&BackgroundTask> {
553 self.registered_tasks
554 .get(&task_type)
555 .map(|tasks| tasks.iter().collect())
556 .unwrap_or_default()
557 }
558}
559
560impl Default for TaskRegistry {
561 fn default() -> Self {
562 Self::new()
563 }
564}
565
566impl SchedulingStrategy {
567 pub fn priority_order(&self) -> u8 {
569 match self {
570 SchedulingStrategy::Immediate => 0,
571 SchedulingStrategy::NetworkOptimal => 1,
572 SchedulingStrategy::BatteryOptimal => 2,
573 SchedulingStrategy::ThermalOptimal => 3,
574 SchedulingStrategy::UserIdle => 4,
575 SchedulingStrategy::OpportunisticAgg => 5,
576 SchedulingStrategy::Deferred => 6,
577 }
578 }
579}
580
581impl Default for ResourceRequirements {
582 fn default() -> Self {
583 Self {
584 min_cpu_percent: 10,
585 max_cpu_percent: 50,
586 min_memory_mb: 50,
587 max_memory_mb: 200,
588 network_bandwidth_mbps: None,
589 requires_gpu: false,
590 storage_io_mbps: None,
591 estimated_execution_time_seconds: 30,
592 }
593 }
594}
595
596impl Default for ExecutionConstraints {
597 fn default() -> Self {
598 Self {
599 max_execution_time_seconds: 300, retry_attempts: 3,
601 retry_delay_seconds: 5,
602 requires_network: false,
603 min_battery_percent: 20,
604 max_thermal_level: crate::lifecycle::config::ThermalLevel::Moderate,
605 background_eligible: true,
606 requires_user_presence: false,
607 }
608 }
609}