1use scirs2_core::ndarray::Array2;
142use sklears_core::error::{Result as SklResult, SklearsError};
143use std::any::Any;
144use std::collections::HashMap;
145use std::fmt;
146use std::future::Future;
147use std::pin::Pin;
148use std::sync::Arc;
149use std::time::{Duration, SystemTime};
150
151#[derive(Clone)]
153pub struct ExecutionTask {
154 pub metadata: TaskMetadata,
156 pub requirements: TaskRequirements,
158 pub constraints: TaskConstraints,
160 pub execution_fn: Option<TaskExecutionFunction>,
162 pub status: TaskStatus,
164 pub context: Option<TaskContext>,
166 pub result: Option<TaskResult>,
168}
169
170impl std::fmt::Debug for ExecutionTask {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 f.debug_struct("ExecutionTask")
173 .field("metadata", &self.metadata)
174 .field("requirements", &self.requirements)
175 .field("constraints", &self.constraints)
176 .field(
177 "execution_fn",
178 &match &self.execution_fn {
179 Some(_) => "<function>",
180 None => "<none>",
181 },
182 )
183 .field("status", &self.status)
184 .field("context", &self.context)
185 .field("result", &self.result)
186 .finish()
187 }
188}
189
190pub type TaskExecutionFunction =
192 Arc<dyn Fn() -> Pin<Box<dyn Future<Output = SklResult<TaskResult>> + Send>> + Send + Sync>;
193
194#[derive(Debug, Clone)]
196pub struct TaskMetadata {
197 pub id: String,
199 pub name: String,
201 pub task_type: TaskType,
203 pub priority: TaskPriority,
205 pub created_at: SystemTime,
207 pub owner: String,
209 pub project: String,
211 pub description: String,
213 pub tags: Vec<String>,
215 pub estimated_duration: Option<Duration>,
217 pub estimated_output_size: Option<u64>,
219 pub cost_budget: Option<f64>,
221 pub version: String,
223 pub dependencies: Vec<String>,
225 pub custom_fields: HashMap<String, String>,
227}
228
229#[derive(Debug, Clone, Default)]
231pub struct TaskRequirements {
232 pub cpu_cores: Option<usize>,
234 pub memory: Option<u64>,
236 pub gpu_devices: Vec<String>,
238 pub gpu_memory: Option<u64>,
240 pub disk_space: Option<u64>,
242 pub network_bandwidth: Option<u64>,
244 pub max_latency: Option<Duration>,
246 pub max_duration: Option<Duration>,
248 pub min_performance_score: Option<f64>,
250 pub software_dependencies: Vec<SoftwareDependency>,
252 pub hardware_requirements: HardwareRequirements,
254 pub data_dependencies: Vec<DataDependency>,
256 pub service_dependencies: Vec<ServiceDependency>,
258 pub dependencies: Vec<String>,
260 pub input_data_size: Option<u64>,
262 pub output_data_size: Option<u64>,
264}
265
266#[derive(Debug, Clone)]
268pub struct SoftwareDependency {
269 pub name: String,
271 pub version: String,
273 pub source: String,
275 pub optional: bool,
277 pub install_command: Option<String>,
279}
280
281#[derive(Debug, Clone, Default)]
283pub struct HardwareRequirements {
284 pub cpu_architecture: Option<CpuArchitecture>,
286 pub min_cpu_frequency: Option<f64>,
288 pub required_instruction_sets: Vec<InstructionSet>,
290 pub gpu_architecture: Option<GpuArchitecture>,
292 pub min_gpu_compute_capability: Option<String>,
294 pub memory_type: Option<MemoryType>,
296 pub storage_type: Option<StorageType>,
298 pub network_requirements: NetworkRequirements,
300}
301
302#[derive(Debug, Clone, PartialEq)]
304pub enum CpuArchitecture {
305 X86_64,
307 Aarch64,
309 Arm,
311 Riscv64,
313 Power,
315 Sparc,
317}
318
319#[derive(Debug, Clone, PartialEq)]
321pub enum InstructionSet {
322 AVX,
324 AVX2,
326 AVX512,
328 SSE2,
330 SSE3,
332 SSE4_1,
334 SSE4_2,
336 NEON,
338 SVE,
340}
341
342#[derive(Debug, Clone, PartialEq)]
344pub enum GpuArchitecture {
345 CUDA,
347 ROCm,
349 OpenCL,
351 Metal,
353 Vulkan,
355 DirectML,
357}
358
359#[derive(Debug, Clone, PartialEq)]
361pub enum MemoryType {
362 DDR4,
364 DDR5,
366 HBM2,
368 HBM3,
370 LPDDR5,
372}
373
374#[derive(Debug, Clone, PartialEq)]
376pub enum StorageType {
377 SSD,
379 NVMe,
381 HDD,
383 MemoryMapped,
385 Network,
387}
388
389#[derive(Debug, Clone, Default)]
391pub struct NetworkRequirements {
392 pub min_bandwidth: Option<u64>,
394 pub max_latency: Option<Duration>,
396 pub protocols: Vec<NetworkProtocol>,
398 pub security_requirements: Vec<SecurityRequirement>,
400}
401
402#[derive(Debug, Clone, PartialEq)]
404pub enum NetworkProtocol {
405 TCP,
407 UDP,
409 HTTP,
411 HTTPS,
413 gRPC,
414 WebSocket,
416 MQTT,
418 InfiniBand,
420}
421
422#[derive(Debug, Clone, PartialEq)]
424pub enum SecurityRequirement {
425 TLS,
427 mTLS,
428 OAuth2,
430 JWT,
432 RBAC,
434 Encryption,
436 VPN,
438}
439
440#[derive(Debug, Clone)]
442pub struct DataDependency {
443 pub source: String,
445 pub format: DataFormat,
447 pub size: Option<u64>,
449 pub access_pattern: DataAccessPattern,
451 pub locality_preference: DataLocality,
453 pub freshness_requirement: Option<Duration>,
455}
456
457#[derive(Debug, Clone, PartialEq)]
459pub enum DataFormat {
460 CSV,
462 Parquet,
464 JSON,
466 JSONL,
468 Avro,
470 ORC,
472 HDF5,
474 NumPy,
476 Arrow,
478 Custom(String),
480}
481
482#[derive(Debug, Clone, PartialEq)]
484pub enum DataAccessPattern {
485 Sequential,
487 Random,
489 Streaming,
491 Batch,
493 Interactive,
495}
496
497#[derive(Debug, Clone, PartialEq)]
499pub enum DataLocality {
500 Local,
502 Regional,
504 Global,
506 Edge,
508 NoPreference,
510}
511
512#[derive(Debug, Clone)]
514pub struct ServiceDependency {
515 pub name: String,
517 pub endpoint: String,
519 pub version: Option<String>,
521 pub auth_requirements: Vec<AuthRequirement>,
523 pub sla_requirements: SlaRequirements,
525}
526
527#[derive(Debug, Clone, PartialEq)]
529pub enum AuthRequirement {
530 ApiKey,
532 Bearer,
534 Basic,
536 OAuth2,
538 Custom(String),
540}
541
542#[derive(Debug, Clone)]
544pub struct SlaRequirements {
545 pub max_response_time: Option<Duration>,
547 pub min_availability: Option<f64>,
549 pub max_error_rate: Option<f64>,
551}
552
553#[derive(Debug, Clone)]
555pub struct TaskConstraints {
556 pub can_be_preempted: bool,
558 pub requires_exclusive_access: bool,
560 pub timeout: Option<Duration>,
562 pub retry_policy: Option<RetryPolicy>,
564 pub affinity: Option<TaskAffinity>,
566 pub anti_affinity: Option<TaskAntiAffinity>,
568 pub location_constraint: Option<ExecutionLocation>,
570 pub security_constraints: SecurityConstraints,
572 pub checkpoint_interval: Option<Duration>,
574 pub cleanup_policy: CleanupPolicy,
576 pub scaling_constraints: ScalingConstraints,
578}
579
580#[derive(Debug, Clone)]
582pub struct RetryPolicy {
583 pub max_attempts: u32,
585 pub backoff_strategy: BackoffStrategy,
587 pub retry_conditions: Vec<RetryCondition>,
589 pub max_retry_time: Option<Duration>,
591}
592
593#[derive(Debug, Clone)]
595pub enum BackoffStrategy {
596 Fixed { delay: u64 },
598 Linear { base: u64, increment: u64 },
600 Exponential { base: u64, max: u64 },
602 ExponentialJitter { base: u64, max: u64, jitter: f64 },
604}
605
606#[derive(Debug, Clone, PartialEq)]
608pub enum RetryCondition {
609 NetworkFailure,
611 ResourceUnavailable,
613 Timeout,
615 TransientError,
617 Custom(String),
619}
620
621#[derive(Debug, Clone, PartialEq)]
623pub enum TaskAffinity {
624 CpuOptimized,
626 GpuOptimized,
628 MemoryOptimized,
630 NetworkOptimized,
632 StorageOptimized,
634 EnergyEfficient,
636 NodeAffinity(String),
638 Custom(String),
640}
641
642#[derive(Debug, Clone)]
644pub struct TaskAntiAffinity {
645 pub node_anti_affinity: Vec<String>,
647 pub temporal_anti_affinity: Vec<String>,
649 pub resource_anti_affinity: Vec<String>,
651}
652
653#[derive(Debug, Clone, PartialEq)]
655pub enum ExecutionLocation {
656 OnPremise,
658 Cloud,
660 Edge,
662 CloudProvider(String),
664 Region(String),
666 AvailabilityZone(String),
668 Cluster(String),
670 Node(String),
672 Hybrid,
674 CloudCluster,
676}
677
678#[derive(Debug, Clone)]
680pub struct SecurityConstraints {
681 pub security_level: SecurityLevel,
683 pub data_classification: DataClassification,
685 pub compliance_requirements: Vec<ComplianceStandard>,
687 pub encryption_requirements: EncryptionRequirements,
689 pub access_control: AccessControlRequirements,
691}
692
693#[derive(Debug, Clone, PartialEq)]
695pub enum SecurityLevel {
696 Public,
698 Internal,
700 Confidential,
702 Secret,
704 TopSecret,
706}
707
708#[derive(Debug, Clone, PartialEq)]
710pub enum DataClassification {
711 Public,
713 Internal,
715 Sensitive,
717 Restricted,
719 Confidential,
721}
722
723#[derive(Debug, Clone, PartialEq)]
725pub enum ComplianceStandard {
726 GDPR,
728 HIPAA,
730 SOC2,
732 ISO27001,
734 FISMA,
736 PCI_DSS,
738 Custom(String),
740}
741
742#[derive(Debug, Clone, Default)]
744pub struct EncryptionRequirements {
745 pub at_rest: bool,
747 pub in_transit: bool,
749 pub in_use: bool,
751 pub algorithms: Vec<EncryptionAlgorithm>,
753}
754
755#[derive(Debug, Clone, PartialEq)]
757pub enum EncryptionAlgorithm {
758 AES256,
759 AES128,
760 RSA2048,
761 RSA4096,
762 ChaCha20,
763 Custom(String),
764}
765
766#[derive(Debug, Clone, Default)]
768pub struct AccessControlRequirements {
769 pub authentication: Vec<AuthenticationMethod>,
771 pub authorization: Vec<AuthorizationPolicy>,
773 pub audit_requirements: AuditRequirements,
775}
776
777#[derive(Debug, Clone, PartialEq)]
779pub enum AuthenticationMethod {
780 Password,
782 MFA,
784 Certificate,
786 Biometric,
788 SSO,
790 LDAP,
792 Custom(String),
794}
795
796#[derive(Debug, Clone, PartialEq)]
798pub enum AuthorizationPolicy {
799 RBAC,
801 ABAC,
803 DAC,
805 MAC,
807 Custom(String),
809}
810
811#[derive(Debug, Clone, Default)]
813pub struct AuditRequirements {
814 pub enabled: bool,
816 pub retention_period: Option<Duration>,
818 pub events: Vec<AuditEvent>,
820}
821
822#[derive(Debug, Clone, PartialEq)]
824pub enum AuditEvent {
825 Access,
827 Modification,
829 Deletion,
831 Export,
833 Authentication,
835 Authorization,
837 Custom(String),
839}
840
841#[derive(Debug, Clone)]
843pub struct CleanupPolicy {
844 pub strategy: CleanupStrategy,
846 pub delay: Option<Duration>,
848 pub preserve_resources: Vec<String>,
850 pub timeout: Option<Duration>,
852}
853
854#[derive(Debug, Clone, PartialEq)]
856pub enum CleanupStrategy {
857 Immediate,
859 Delayed,
861 Manual,
863 Conditional(String),
865 None,
867}
868
869#[derive(Debug, Clone)]
871pub struct ScalingConstraints {
872 pub horizontal_scaling: bool,
874 pub vertical_scaling: bool,
876 pub min_instances: Option<usize>,
878 pub max_instances: Option<usize>,
880 pub scaling_triggers: Vec<ScalingTrigger>,
882 pub cooldown_period: Option<Duration>,
884}
885
886#[derive(Debug, Clone)]
888pub enum ScalingTrigger {
889 CpuUtilization(f64),
891 MemoryUtilization(f64),
893 QueueDepth(usize),
895 CustomMetric { name: String, threshold: f64 },
897}
898
899#[derive(Debug, Clone, PartialEq)]
901pub enum TaskStatus {
902 Created,
904 Queued,
906 Scheduled,
908 Running,
910 Paused,
912 Completed,
914 Failed(TaskError),
916 Cancelled,
918 TimedOut,
920 Retrying,
922 CleaningUp,
924}
925
926#[derive(Debug, Clone, PartialEq)]
928pub enum TaskType {
929 Preprocess,
931 Fit,
933 Predict,
935 Transform,
937 Evaluate,
939 Validate,
941 Deploy,
943 Monitor,
945 Cleanup,
947 Custom(String),
949}
950
951#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
953pub enum TaskPriority {
954 Lowest,
956 Low,
958 Normal,
960 High,
962 Highest,
964 Critical,
966}
967
968#[derive(Debug, Clone, PartialEq)]
970pub enum TaskError {
971 ResourceAllocation(String),
973 DependencyFailure(String),
975 Timeout,
977 RuntimeError(String),
979 ValidationError(String),
981 InfrastructureError(String),
983 SecurityViolation(String),
985 Custom(String),
987}
988
989#[derive(Debug, Clone)]
991pub struct TaskResult {
992 pub task_id: String,
994 pub status: TaskStatus,
996 pub output: Option<TaskOutput>,
998 pub metrics: TaskExecutionMetrics,
1000 pub resource_usage: TaskResourceUsage,
1002 pub performance_metrics: TaskPerformanceMetrics,
1004 pub error: Option<TaskError>,
1006 pub logs: Vec<LogEntry>,
1008 pub artifacts: Vec<Artifact>,
1010 pub execution_time: Option<Duration>,
1012 pub metadata: HashMap<String, String>,
1014}
1015
1016#[derive(Debug)]
1018pub enum TaskOutput {
1019 Array(Array2<f64>),
1021 Text(String),
1023 Binary(Vec<u8>),
1025 Json(String),
1027 FilePath(String),
1029 Multiple(HashMap<String, Box<TaskOutput>>),
1031 Custom(Box<dyn Any + Send + Sync>),
1033}
1034
1035impl Clone for TaskOutput {
1036 fn clone(&self) -> Self {
1037 match self {
1038 TaskOutput::Array(arr) => TaskOutput::Array(arr.clone()),
1039 TaskOutput::Text(text) => TaskOutput::Text(text.clone()),
1040 TaskOutput::Binary(data) => TaskOutput::Binary(data.clone()),
1041 TaskOutput::Json(json) => TaskOutput::Json(json.clone()),
1042 TaskOutput::FilePath(path) => TaskOutput::FilePath(path.clone()),
1043 TaskOutput::Multiple(map) => TaskOutput::Multiple(map.clone()),
1044 TaskOutput::Custom(_) => {
1045 TaskOutput::Text("Custom output (clone not supported)".to_string())
1047 }
1048 }
1049 }
1050}
1051
1052#[derive(Debug, Clone, Default)]
1054pub struct TaskResourceUsage {
1055 pub cpu_time: f64,
1057 pub memory_usage: u64,
1059 pub peak_memory_usage: u64,
1061 pub disk_io_operations: u64,
1063 pub network_usage: u64,
1065 pub gpu_usage: Option<f64>,
1067 pub gpu_memory_usage: Option<u64>,
1069}
1070
1071#[derive(Debug, Clone, Default)]
1073pub struct TaskPerformanceMetrics {
1074 pub operations_per_second: f64,
1076 pub throughput: f64,
1078 pub latency: Duration,
1080 pub error_rate: f64,
1082 pub cache_hit_rate: Option<f64>,
1084 pub efficiency_score: f64,
1086}
1087
1088#[derive(Debug, Clone)]
1090pub struct LogEntry {
1091 pub timestamp: SystemTime,
1093 pub level: LogLevel,
1095 pub message: String,
1097 pub source: String,
1099}
1100
1101#[derive(Debug, Clone)]
1103pub enum LogLevel {
1104 Debug,
1106 Info,
1108 Warning,
1110 Error,
1112}
1113
1114#[derive(Debug, Clone)]
1116pub struct Artifact {
1117 pub name: String,
1119 pub artifact_type: ArtifactType,
1121 pub location: String,
1123 pub size: u64,
1125 pub created_at: SystemTime,
1127 pub content_hash: Option<String>,
1129}
1130
1131#[derive(Debug, Clone)]
1133pub enum ArtifactType {
1134 OutputFile,
1136 LogFile,
1138 IntermediateResult,
1140 CacheFile,
1142 Report,
1144 Custom(String),
1146}
1147
1148#[derive(Debug, Clone)]
1150pub struct TaskExecutionMetrics {
1151 pub start_time: SystemTime,
1153 pub end_time: Option<SystemTime>,
1155 pub duration: Option<Duration>,
1157 pub queue_wait_time: Duration,
1159 pub scheduling_time: Duration,
1161 pub setup_time: Duration,
1163 pub cleanup_time: Duration,
1165 pub retry_attempts: u32,
1167 pub checkpoint_count: u32,
1169 pub completion_percentage: f64,
1171 pub efficiency_score: Option<f64>,
1173}
1174
1175impl Default for TaskExecutionMetrics {
1176 fn default() -> Self {
1177 Self {
1178 start_time: SystemTime::now(),
1179 end_time: None,
1180 duration: None,
1181 queue_wait_time: Duration::from_secs(0),
1182 scheduling_time: Duration::from_secs(0),
1183 setup_time: Duration::from_secs(0),
1184 cleanup_time: Duration::from_secs(0),
1185 retry_attempts: 0,
1186 checkpoint_count: 0,
1187 completion_percentage: 0.0,
1188 efficiency_score: None,
1189 }
1190 }
1191}
1192
1193#[derive(Debug, Clone)]
1195pub struct TaskContext {
1196 pub id: String,
1198 pub environment: HashMap<String, String>,
1200 pub working_directory: String,
1202 pub allocated_resources: AllocatedResources,
1204 pub state: TaskExecutionState,
1206 pub progress: TaskProgress,
1208 pub channels: CommunicationChannels,
1210}
1211
1212#[derive(Debug, Clone)]
1214pub struct AllocatedResources {
1215 pub cpu_cores: Vec<usize>,
1217 pub memory: u64,
1219 pub gpu_devices: Vec<String>,
1221 pub storage_space: u64,
1223 pub network_bandwidth: u64,
1225 pub allocated_at: SystemTime,
1227}
1228
1229#[derive(Debug, Clone)]
1231pub struct TaskExecutionState {
1232 pub phase: ExecutionPhase,
1234 pub progress_percentage: f64,
1236 pub current_operation: String,
1238 pub estimated_time_remaining: Option<Duration>,
1240 pub metrics_snapshots: Vec<MetricsSnapshot>,
1242}
1243
1244#[derive(Debug, Clone, PartialEq)]
1246pub enum ExecutionPhase {
1247 Initialization,
1249 Setup,
1251 Execution,
1253 Cleanup,
1255 Finalization,
1257}
1258
1259#[derive(Debug, Clone)]
1261pub struct TaskProgress {
1262 pub total_work: Option<u64>,
1264 pub completed_work: u64,
1266 pub percentage: f64,
1268 pub current_milestone: String,
1270 pub estimated_completion: Option<SystemTime>,
1272}
1273
1274#[derive(Debug, Clone)]
1276pub struct CommunicationChannels {
1277 pub command_channel: Option<String>,
1279 pub status_channel: Option<String>,
1281 pub progress_channel: Option<String>,
1283 pub error_channel: Option<String>,
1285}
1286
1287#[derive(Debug, Clone)]
1289pub struct MetricsSnapshot {
1290 pub timestamp: SystemTime,
1292 pub cpu_usage: f64,
1294 pub memory_usage: u64,
1296 pub gpu_usage: Option<f64>,
1298 pub custom_metrics: HashMap<String, f64>,
1300}
1301
1302pub struct TaskBuilder {
1304 metadata: TaskMetadata,
1305 requirements: TaskRequirements,
1306 constraints: TaskConstraints,
1307 execution_fn: Option<TaskExecutionFunction>,
1308}
1309
1310impl std::fmt::Debug for TaskBuilder {
1311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1312 f.debug_struct("TaskBuilder")
1313 .field("metadata", &self.metadata)
1314 .field("requirements", &self.requirements)
1315 .field("constraints", &self.constraints)
1316 .field(
1317 "execution_fn",
1318 &match &self.execution_fn {
1319 Some(_) => "<function>",
1320 None => "<none>",
1321 },
1322 )
1323 .finish()
1324 }
1325}
1326
1327impl Default for TaskBuilder {
1328 fn default() -> Self {
1329 Self::new()
1330 }
1331}
1332
1333impl TaskBuilder {
1334 #[must_use]
1336 pub fn new() -> Self {
1337 Self {
1338 metadata: TaskMetadata::default(),
1339 requirements: TaskRequirements::default(),
1340 constraints: TaskConstraints::default(),
1341 execution_fn: None,
1342 }
1343 }
1344
1345 #[must_use]
1347 pub fn name(mut self, name: &str) -> Self {
1348 self.metadata.name = name.to_string();
1349 self
1350 }
1351
1352 #[must_use]
1354 pub fn task_type(mut self, task_type: TaskType) -> Self {
1355 self.metadata.task_type = task_type;
1356 self
1357 }
1358
1359 #[must_use]
1361 pub fn priority(mut self, priority: TaskPriority) -> Self {
1362 self.metadata.priority = priority;
1363 self
1364 }
1365
1366 #[must_use]
1368 pub fn requirements(mut self, requirements: TaskRequirements) -> Self {
1369 self.requirements = requirements;
1370 self
1371 }
1372
1373 #[must_use]
1375 pub fn constraints(mut self, constraints: TaskConstraints) -> Self {
1376 self.constraints = constraints;
1377 self
1378 }
1379
1380 #[must_use]
1382 pub fn metadata(mut self, metadata: TaskMetadata) -> Self {
1383 self.metadata = metadata;
1384 self
1385 }
1386
1387 pub fn execution_fn(mut self, func: TaskExecutionFunction) -> Self {
1389 self.execution_fn = Some(func);
1390 self
1391 }
1392
1393 #[must_use]
1395 pub fn build(self) -> ExecutionTask {
1396 ExecutionTask {
1398 metadata: self.metadata,
1399 requirements: self.requirements,
1400 constraints: self.constraints,
1401 execution_fn: self.execution_fn,
1402 status: TaskStatus::Created,
1403 context: None,
1404 result: None,
1405 }
1406 }
1407}
1408
1409pub struct TaskValidator;
1411
1412impl TaskValidator {
1413 pub fn validate(task: &ExecutionTask) -> SklResult<()> {
1415 Self::validate_metadata(&task.metadata)?;
1417
1418 Self::validate_requirements(&task.requirements)?;
1420
1421 Self::validate_constraints(&task.constraints)?;
1423
1424 Ok(())
1425 }
1426
1427 fn validate_metadata(metadata: &TaskMetadata) -> SklResult<()> {
1428 if metadata.name.is_empty() {
1429 return Err(SklearsError::InvalidInput(
1430 "Task name cannot be empty".to_string(),
1431 ));
1432 }
1433
1434 if metadata.id.is_empty() {
1435 return Err(SklearsError::InvalidInput(
1436 "Task ID cannot be empty".to_string(),
1437 ));
1438 }
1439
1440 Ok(())
1441 }
1442
1443 fn validate_requirements(requirements: &TaskRequirements) -> SklResult<()> {
1444 if let Some(cores) = requirements.cpu_cores {
1445 if cores == 0 {
1446 return Err(SklearsError::InvalidInput(
1447 "CPU cores must be greater than 0".to_string(),
1448 ));
1449 }
1450 }
1451
1452 if let Some(memory) = requirements.memory {
1453 if memory == 0 {
1454 return Err(SklearsError::InvalidInput(
1455 "Memory must be greater than 0".to_string(),
1456 ));
1457 }
1458 }
1459
1460 Ok(())
1461 }
1462
1463 fn validate_constraints(constraints: &TaskConstraints) -> SklResult<()> {
1464 if let Some(timeout) = constraints.timeout {
1465 if timeout.as_secs() == 0 {
1466 return Err(SklearsError::InvalidInput(
1467 "Timeout must be greater than 0".to_string(),
1468 ));
1469 }
1470 }
1471
1472 Ok(())
1473 }
1474}
1475
1476impl Default for TaskMetadata {
1478 fn default() -> Self {
1479 Self {
1480 id: uuid::Uuid::new_v4().to_string(),
1481 name: "unnamed_task".to_string(),
1482 task_type: TaskType::Custom("generic".to_string()),
1483 priority: TaskPriority::Normal,
1484 created_at: SystemTime::now(),
1485 owner: "unknown".to_string(),
1486 project: "default".to_string(),
1487 description: String::new(),
1488 tags: Vec::new(),
1489 estimated_duration: None,
1490 estimated_output_size: None,
1491 cost_budget: None,
1492 version: "1.0.0".to_string(),
1493 dependencies: Vec::new(),
1494 custom_fields: HashMap::new(),
1495 }
1496 }
1497}
1498
1499impl Default for TaskConstraints {
1500 fn default() -> Self {
1501 Self {
1502 can_be_preempted: true,
1503 requires_exclusive_access: false,
1504 timeout: None,
1505 retry_policy: None,
1506 affinity: None,
1507 anti_affinity: None,
1508 location_constraint: None,
1509 security_constraints: SecurityConstraints::default(),
1510 checkpoint_interval: None,
1511 cleanup_policy: CleanupPolicy::default(),
1512 scaling_constraints: ScalingConstraints::default(),
1513 }
1514 }
1515}
1516
1517impl Default for SecurityConstraints {
1518 fn default() -> Self {
1519 Self {
1520 security_level: SecurityLevel::Internal,
1521 data_classification: DataClassification::Internal,
1522 compliance_requirements: Vec::new(),
1523 encryption_requirements: EncryptionRequirements::default(),
1524 access_control: AccessControlRequirements::default(),
1525 }
1526 }
1527}
1528
1529impl Default for CleanupPolicy {
1530 fn default() -> Self {
1531 Self {
1532 strategy: CleanupStrategy::Delayed,
1533 delay: Some(Duration::from_secs(300)), preserve_resources: Vec::new(),
1535 timeout: Some(Duration::from_secs(600)), }
1537 }
1538}
1539
1540impl Default for ScalingConstraints {
1541 fn default() -> Self {
1542 Self {
1543 horizontal_scaling: false,
1544 vertical_scaling: false,
1545 min_instances: Some(1),
1546 max_instances: Some(10),
1547 scaling_triggers: Vec::new(),
1548 cooldown_period: Some(Duration::from_secs(300)), }
1550 }
1551}
1552
1553impl ExecutionTask {
1554 #[must_use]
1556 pub fn builder() -> TaskBuilder {
1557 TaskBuilder::new()
1558 }
1559
1560 pub fn new(name: &str, task_type: TaskType, execution_fn: TaskExecutionFunction) -> Self {
1562 Self::builder()
1563 .name(name)
1564 .task_type(task_type)
1565 .execution_fn(execution_fn)
1566 .build()
1567 }
1568
1569 #[must_use]
1571 pub fn id(&self) -> &str {
1572 &self.metadata.id
1573 }
1574
1575 #[must_use]
1577 pub fn name(&self) -> &str {
1578 &self.metadata.name
1579 }
1580
1581 #[must_use]
1583 pub fn status(&self) -> &TaskStatus {
1584 &self.status
1585 }
1586
1587 pub fn set_status(&mut self, status: TaskStatus) {
1589 self.status = status;
1590 }
1591
1592 #[must_use]
1594 pub fn is_complete(&self) -> bool {
1595 matches!(
1596 self.status,
1597 TaskStatus::Completed | TaskStatus::Failed(_) | TaskStatus::Cancelled
1598 )
1599 }
1600
1601 #[must_use]
1603 pub fn can_retry(&self) -> bool {
1604 if let Some(retry_policy) = &self.constraints.retry_policy {
1605 if let TaskStatus::Failed(_) = self.status {
1606 return retry_policy.max_attempts > 0;
1607 }
1608 }
1609 false
1610 }
1611
1612 pub fn validate(&self) -> SklResult<()> {
1614 TaskValidator::validate(self)
1615 }
1616}
1617
1618impl fmt::Display for TaskError {
1619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1620 match self {
1621 TaskError::ResourceAllocation(msg) => write!(f, "Resource allocation error: {msg}"),
1622 TaskError::DependencyFailure(msg) => write!(f, "Dependency failure: {msg}"),
1623 TaskError::Timeout => write!(f, "Task timeout"),
1624 TaskError::RuntimeError(msg) => write!(f, "Runtime error: {msg}"),
1625 TaskError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
1626 TaskError::InfrastructureError(msg) => write!(f, "Infrastructure error: {msg}"),
1627 TaskError::SecurityViolation(msg) => write!(f, "Security violation: {msg}"),
1628 TaskError::Custom(msg) => write!(f, "Custom error: {msg}"),
1629 }
1630 }
1631}
1632
1633impl std::error::Error for TaskError {}
1634
1635extern crate uuid;
1637
1638#[allow(non_snake_case)]
1639#[cfg(test)]
1640mod tests {
1641 use super::*;
1642
1643 #[test]
1644 fn test_task_builder() {
1645 let task = ExecutionTask::builder()
1646 .name("test_task")
1647 .task_type(TaskType::Preprocess)
1648 .priority(TaskPriority::High)
1649 .build();
1650
1651 assert_eq!(task.name(), "test_task");
1652 assert_eq!(task.metadata.task_type, TaskType::Preprocess);
1653 assert_eq!(task.metadata.priority, TaskPriority::High);
1654 assert_eq!(task.status, TaskStatus::Created);
1655 }
1656
1657 #[test]
1658 fn test_task_validation() {
1659 let task = ExecutionTask::builder()
1660 .name("valid_task")
1661 .task_type(TaskType::Fit)
1662 .build();
1663
1664 assert!(task.validate().is_ok());
1665 }
1666
1667 #[test]
1668 fn test_task_requirements() {
1669 let requirements = TaskRequirements {
1670 cpu_cores: Some(4),
1671 memory: Some(8 * 1024 * 1024 * 1024), gpu_devices: vec!["cuda:0".to_string()],
1673 ..Default::default()
1674 };
1675
1676 assert_eq!(requirements.cpu_cores, Some(4));
1677 assert_eq!(requirements.memory, Some(8 * 1024 * 1024 * 1024));
1678 assert_eq!(requirements.gpu_devices.len(), 1);
1679 }
1680
1681 #[test]
1682 fn test_task_constraints() {
1683 let constraints = TaskConstraints {
1684 can_be_preempted: false,
1685 requires_exclusive_access: true,
1686 timeout: Some(Duration::from_secs(3600)),
1687 ..Default::default()
1688 };
1689
1690 assert!(!constraints.can_be_preempted);
1691 assert!(constraints.requires_exclusive_access);
1692 assert_eq!(constraints.timeout, Some(Duration::from_secs(3600)));
1693 }
1694
1695 #[test]
1696 fn test_task_priorities() {
1697 assert!(TaskPriority::Critical > TaskPriority::High);
1698 assert!(TaskPriority::High > TaskPriority::Normal);
1699 assert!(TaskPriority::Normal > TaskPriority::Low);
1700 assert!(TaskPriority::Low > TaskPriority::Lowest);
1701 }
1702
1703 #[test]
1704 fn test_task_status_transitions() {
1705 let mut task = ExecutionTask::builder().name("status_test").build();
1706
1707 assert_eq!(task.status(), &TaskStatus::Created);
1708
1709 task.set_status(TaskStatus::Queued);
1710 assert_eq!(task.status(), &TaskStatus::Queued);
1711
1712 task.set_status(TaskStatus::Running);
1713 assert_eq!(task.status(), &TaskStatus::Running);
1714
1715 task.set_status(TaskStatus::Completed);
1716 assert_eq!(task.status(), &TaskStatus::Completed);
1717 assert!(task.is_complete());
1718 }
1719
1720 #[test]
1721 fn test_metadata_default() {
1722 let metadata = TaskMetadata::default();
1723 assert!(!metadata.id.is_empty());
1724 assert_eq!(metadata.name, "unnamed_task");
1725 assert_eq!(metadata.priority, TaskPriority::Normal);
1726 assert_eq!(metadata.owner, "unknown");
1727 }
1728
1729 #[test]
1730 fn test_retry_policy() {
1731 let retry_policy = RetryPolicy {
1732 max_attempts: 3,
1733 backoff_strategy: BackoffStrategy::Exponential {
1734 base: 1000,
1735 max: 30000,
1736 },
1737 retry_conditions: vec![RetryCondition::NetworkFailure, RetryCondition::Timeout],
1738 max_retry_time: Some(Duration::from_secs(300)),
1739 };
1740
1741 assert_eq!(retry_policy.max_attempts, 3);
1742 assert!(matches!(
1743 retry_policy.backoff_strategy,
1744 BackoffStrategy::Exponential { .. }
1745 ));
1746 assert_eq!(retry_policy.retry_conditions.len(), 2);
1747 }
1748
1749 #[test]
1750 fn test_security_constraints() {
1751 let security = SecurityConstraints {
1752 security_level: SecurityLevel::Confidential,
1753 data_classification: DataClassification::Sensitive,
1754 compliance_requirements: vec![ComplianceStandard::GDPR, ComplianceStandard::HIPAA],
1755 ..Default::default()
1756 };
1757
1758 assert_eq!(security.security_level, SecurityLevel::Confidential);
1759 assert_eq!(security.data_classification, DataClassification::Sensitive);
1760 assert_eq!(security.compliance_requirements.len(), 2);
1761 }
1762}