Skip to main content

hammerwork_web/api/
spawn.rs

1//! Job spawning and dependency management API endpoints.
2//!
3//! This module provides REST API endpoints for managing job spawn operations,
4//! spawn tree hierarchies, and parent-child relationships between jobs.
5//!
6//! Note: This is a placeholder implementation for spawn API endpoints.
7//! The actual database queries and spawn logic will be implemented based on
8//! the specific database backend being used.
9
10use chrono::{DateTime, Utc};
11use hammerwork::queue::DatabaseQueue;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::sync::Arc;
15use uuid::Uuid;
16use warp::{Filter, Rejection, Reply};
17
18use super::ApiResponse;
19
20/// Parameters for querying spawn children
21#[derive(Debug, Deserialize)]
22pub struct SpawnChildrenParams {
23    /// Include grandchildren and deeper descendants
24    pub include_grandchildren: Option<bool>,
25    /// Filter children by status
26    pub status_filter: Option<String>,
27    /// Maximum depth to traverse (default: 1)
28    pub depth: Option<u32>,
29}
30
31/// Parameters for spawn tree queries
32#[derive(Debug, Deserialize)]
33pub struct SpawnTreeParams {
34    /// Output format (json, mermaid, d3)
35    pub format: Option<String>,
36    /// Maximum depth to include
37    pub max_depth: Option<u32>,
38    /// Include spawn configuration details
39    pub include_config: Option<bool>,
40}
41
42/// Spawn operation details
43#[derive(Debug, Serialize)]
44pub struct SpawnOperationInfo {
45    pub operation_id: String,
46    pub parent_job_id: Uuid,
47    pub spawned_job_ids: Vec<Uuid>,
48    pub spawned_at: DateTime<Utc>,
49    pub spawn_count: u32,
50    pub success_count: u32,
51    pub failed_count: u32,
52    pub pending_count: u32,
53    pub config: Option<serde_json::Value>,
54}
55
56/// Job information for spawn tree nodes
57#[derive(Debug, Serialize)]
58pub struct SpawnTreeNode {
59    pub id: Uuid,
60    pub queue_name: String,
61    pub status: String,
62    pub priority: String,
63    pub created_at: DateTime<Utc>,
64    pub has_spawn_config: bool,
65    pub children: Vec<SpawnTreeNode>,
66    pub parent_id: Option<Uuid>,
67    pub depth: u32,
68    pub spawn_operation_id: Option<String>,
69}
70
71/// Complete spawn tree response
72#[derive(Debug, Serialize)]
73pub struct SpawnTreeResponse {
74    pub root_job: SpawnTreeNode,
75    pub total_nodes: u32,
76    pub max_depth: u32,
77    pub spawn_operations: Vec<SpawnOperationInfo>,
78}
79
80/// Spawn statistics response
81#[derive(Debug, Serialize)]
82pub struct SpawnStatsResponse {
83    pub total_spawn_operations: u64,
84    pub avg_children_per_spawn: f64,
85    pub max_children_in_spawn: u32,
86    pub spawn_success_rate: f64,
87    pub recent_spawn_count: u64,
88    pub queue_breakdown: HashMap<String, SpawnQueueStats>,
89}
90
91/// Per-queue spawn statistics
92#[derive(Debug, Serialize)]
93pub struct SpawnQueueStats {
94    pub spawn_operations: u64,
95    pub avg_children: f64,
96    pub success_rate: f64,
97}
98
99/// Minimal job information for API responses
100#[derive(Debug, Serialize)]
101pub struct JobInfo {
102    pub id: Uuid,
103    pub queue_name: String,
104    pub status: String,
105    pub priority: String,
106    pub created_at: DateTime<Utc>,
107    pub scheduled_at: Option<DateTime<Utc>>,
108    pub started_at: Option<DateTime<Utc>>,
109    pub completed_at: Option<DateTime<Utc>>,
110    pub has_spawn_config: bool,
111    pub spawn_operation_id: Option<String>,
112}
113
114/// Create spawn API routes
115pub fn spawn_routes<T>(
116    _queue: Arc<T>,
117) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone
118where
119    T: DatabaseQueue + Send + Sync + 'static,
120{
121    // Placeholder route that returns a message about spawn API endpoints
122    warp::path("spawn")
123        .and(warp::path("info"))
124        .and(warp::get())
125        .map(|| {
126            let response = ApiResponse::success(serde_json::json!({
127                "message": "Spawn API endpoints are available",
128                "endpoints": [
129                    "GET /api/jobs/{id}/children - List spawned child jobs",
130                    "GET /api/jobs/{id}/parent - Get parent job information",
131                    "GET /api/jobs/{id}/spawn-tree - Get complete spawn hierarchy",
132                    "GET /api/spawn/operations - List spawn operations",
133                    "GET /api/spawn/operations/{id} - Get spawn operation details",
134                    "POST /api/jobs/{id}/spawn - Manually trigger spawn operation",
135                    "GET /api/spawn/stats - Get spawn operation statistics"
136                ],
137                "status": "placeholder_implementation"
138            }));
139            warp::reply::json(&response)
140        })
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn test_spawn_children_params() {
149        let params = SpawnChildrenParams {
150            include_grandchildren: Some(true),
151            status_filter: Some("pending".to_string()),
152            depth: Some(3),
153        };
154
155        assert_eq!(params.include_grandchildren, Some(true));
156        assert_eq!(params.status_filter, Some("pending".to_string()));
157        assert_eq!(params.depth, Some(3));
158    }
159
160    #[test]
161    fn test_spawn_tree_params() {
162        let params = SpawnTreeParams {
163            format: Some("mermaid".to_string()),
164            max_depth: Some(5),
165            include_config: Some(true),
166        };
167
168        assert_eq!(params.format, Some("mermaid".to_string()));
169        assert_eq!(params.max_depth, Some(5));
170        assert_eq!(params.include_config, Some(true));
171    }
172
173    #[test]
174    fn test_spawn_tree_response_structure() {
175        let tree_response = SpawnTreeResponse {
176            root_job: SpawnTreeNode {
177                id: Uuid::new_v4(),
178                queue_name: "test_queue".to_string(),
179                status: "completed".to_string(),
180                priority: "high".to_string(),
181                created_at: Utc::now(),
182                has_spawn_config: true,
183                children: vec![],
184                parent_id: None,
185                depth: 0,
186                spawn_operation_id: Some("test_op".to_string()),
187            },
188            total_nodes: 1,
189            max_depth: 0,
190            spawn_operations: vec![],
191        };
192
193        assert_eq!(tree_response.total_nodes, 1);
194        assert_eq!(tree_response.max_depth, 0);
195        assert!(tree_response.root_job.has_spawn_config);
196    }
197
198    #[test]
199    fn test_spawn_stats_response_structure() {
200        let mut queue_breakdown = HashMap::new();
201        queue_breakdown.insert(
202            "test_queue".to_string(),
203            SpawnQueueStats {
204                spawn_operations: 10,
205                avg_children: 3.5,
206                success_rate: 95.0,
207            },
208        );
209
210        let stats_response = SpawnStatsResponse {
211            total_spawn_operations: 50,
212            avg_children_per_spawn: 3.2,
213            max_children_in_spawn: 15,
214            spawn_success_rate: 97.5,
215            recent_spawn_count: 12,
216            queue_breakdown,
217        };
218
219        assert_eq!(stats_response.total_spawn_operations, 50);
220        assert_eq!(stats_response.avg_children_per_spawn, 3.2);
221        assert_eq!(stats_response.spawn_success_rate, 97.5);
222        assert_eq!(stats_response.queue_breakdown.len(), 1);
223    }
224}