1use serde::{Deserialize, Serialize};
2use stack_ids::{AttemptId, TraceCtx, TrialId};
3use std::time::Duration;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct SchedulingConfig {
11 pub max_consecutive_same_key: usize,
14 #[serde(with = "duration_millis")]
16 pub resource_switch_cooldown: Duration,
17 pub enable_reordering: bool,
19}
20
21impl Default for SchedulingConfig {
22 fn default() -> Self {
23 Self {
24 max_consecutive_same_key: 3,
25 resource_switch_cooldown: Duration::ZERO,
26 enable_reordering: true,
27 }
28 }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub enum EtaConfidence {
35 Low,
37 Medium,
39 High,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct EtaEstimate {
47 pub remaining_ms: u64,
49 pub items_remaining: usize,
51 pub avg_item_ms: u64,
53 pub confidence: EtaConfidence,
55 pub sample_count: u64,
57}
58
59mod duration_millis {
61 use serde::{Deserialize, Deserializer, Serialize, Serializer};
62 use std::time::Duration;
63
64 pub fn serialize<S: Serializer>(d: &Duration, s: S) -> Result<S::Ok, S::Error> {
65 d.as_millis().serialize(s)
66 }
67
68 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Duration, D::Error> {
69 let ms = u64::deserialize(d)?;
70 Ok(Duration::from_millis(ms))
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76#[serde(rename_all = "camelCase")]
77pub enum BatchItemStatus {
78 Pending,
79 Running,
80 Completed,
81 Failed,
82 Skipped,
83 Cancelled,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
88#[serde(rename_all = "camelCase")]
89pub enum BatchJobStatus {
90 Queued,
91 Running,
92 Completed,
93 CompletedWithErrors,
94 Cancelled,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub enum OverwritePolicy {
101 Skip,
103 Overwrite,
105}
106
107#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
109#[serde(rename_all = "camelCase")]
110pub enum SizeBucket {
111 Small,
112 Medium,
113 Large,
114 Unknown,
115}
116
117impl SizeBucket {
118 pub fn from_pixel_count(pixels: u64) -> Self {
120 if pixels < 500_000 {
121 Self::Small
122 } else if pixels < 2_000_000 {
123 Self::Medium
124 } else {
125 Self::Large
126 }
127 }
128
129 pub fn from_dimensions(width: Option<u32>, height: Option<u32>) -> Self {
131 match (width, height) {
132 (Some(w), Some(h)) => Self::from_pixel_count(w as u64 * h as u64),
133 _ => Self::Unknown,
134 }
135 }
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
150#[serde(rename_all = "camelCase")]
151pub struct BatchItem<D>
152where
153 D: Clone + Send + Sync + Serialize,
154{
155 pub id: String,
157 pub data: D,
159 pub status: BatchItemStatus,
161 pub error: Option<String>,
163 pub duration_ms: Option<u64>,
165 pub size_bucket: SizeBucket,
167 #[serde(default, skip_serializing_if = "Option::is_none")]
169 pub trace_ctx: Option<TraceCtx>,
170 #[serde(default, skip_serializing_if = "Option::is_none")]
176 pub attempt_id: Option<AttemptId>,
177 #[serde(default, skip_serializing_if = "Option::is_none")]
182 pub trial_id: Option<TrialId>,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct BatchJob<D>
193where
194 D: Clone + Send + Sync + Serialize,
195{
196 pub id: String,
198 pub resource_key: String,
200 pub operation: String,
202 pub overwrite_policy: OverwritePolicy,
204 pub items: Vec<BatchItem<D>>,
206 pub status: BatchJobStatus,
208 pub created_at: String,
210 pub started_at: Option<String>,
212 pub completed_at: Option<String>,
214 pub reordered: bool,
216 pub reorder_note: Option<String>,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222#[serde(rename_all = "camelCase")]
223pub struct BatchCompletionSummary {
224 pub job_id: String,
225 pub operation: String,
226 pub resource_key: String,
227 pub total: usize,
228 pub succeeded: usize,
229 pub failed: usize,
230 pub skipped: usize,
231 pub total_duration_ms: u64,
232 pub avg_duration_ms: u64,
233}
234
235#[derive(Debug, Clone)]
237pub struct ItemResult {
238 pub success: bool,
240 pub output: Option<String>,
242 pub error: Option<String>,
244}
245
246impl ItemResult {
247 pub fn success() -> Self {
248 Self {
249 success: true,
250 output: None,
251 error: None,
252 }
253 }
254
255 pub fn success_with_output(output: String) -> Self {
256 Self {
257 success: true,
258 output: Some(output),
259 error: None,
260 }
261 }
262
263 pub fn failure(error: String) -> Self {
264 Self {
265 success: false,
266 output: None,
267 error: Some(error),
268 }
269 }
270}