Add sequential batch queue processing

- After a batch completes, automatically start next pending batch
- Mark completed/failed batches in queue with correct status
- Failed batches don't block the queue - next pending batch starts
- Queue processes batches in order, one at a time
This commit is contained in:
2026-03-06 16:17:25 +02:00
parent a0bb00eddf
commit 5a56e25c2c

View File

@@ -1615,6 +1615,7 @@ fn run_processing(_window: &adw::ApplicationWindow, ui: &WizardUi) {
return glib::ControlFlow::Break;
}
ProcessingMessage::Error(err) => {
mark_current_queue_batch(&ui_for_rx, false, Some(&err));
let toast = adw::Toast::new(&format!("Processing failed: {}", err));
ui_for_rx.toast_overlay.add_toast(toast);
ui_for_rx.back_button.set_visible(true);
@@ -1624,6 +1625,11 @@ fn run_processing(_window: &adw::ApplicationWindow, ui: &WizardUi) {
{
ui_for_rx.nav_view.pop();
}
// Try to process next batch even if this one failed
let ui_q = ui_for_rx.clone();
glib::timeout_add_local_once(std::time::Duration::from_millis(500), move || {
process_next_queued_batch(&ui_q);
});
return glib::ControlFlow::Break;
}
}
@@ -1775,6 +1781,15 @@ fn show_results(
);
}
}
// Mark current queue batch as completed and process next one
mark_current_queue_batch(ui, true, None);
// Auto-start next queued batch after a short delay
let ui_for_queue = ui.clone();
glib::timeout_add_local_once(std::time::Duration::from_millis(500), move || {
process_next_queued_batch(&ui_for_queue);
});
}
fn update_results_stats(
@@ -2969,3 +2984,76 @@ fn add_current_batch_to_queue(ui: &WizardUi) {
refresh_queue_list(ui);
ui.toast_overlay.add_toast(adw::Toast::new("Batch added to queue"));
}
/// Check for pending batches in the queue and start processing the next one.
/// Returns true if a batch was started.
fn process_next_queued_batch(ui: &WizardUi) -> bool {
// Find the first pending batch
let next_idx = {
let queue = ui.state.batch_queue.borrow();
queue.batches.iter().position(|b| b.status == BatchStatus::Pending)
};
let Some(idx) = next_idx else {
return false;
};
// Mark it as processing
let batch = {
let mut queue = ui.state.batch_queue.borrow_mut();
queue.batches[idx].status = BatchStatus::Processing;
queue.batches[idx].clone()
};
refresh_queue_list(ui);
// Load the batch's config into state so start_processing uses it
*ui.state.job_config.borrow_mut() = batch.job_config;
*ui.state.loaded_files.borrow_mut() = batch.files;
ui.state.excluded_files.borrow_mut().clear();
*ui.state.output_dir.borrow_mut() = Some(batch.output_dir);
ui.toast_overlay.add_toast(adw::Toast::new(&format!("Starting queued batch: {}", batch.name)));
// Pop to a clean state if we're on results page
while let Some(page) = ui.nav_view.visible_page() {
let tag = page.tag();
if tag.as_deref() == Some("processing") || tag.as_deref() == Some("results") {
ui.nav_view.pop();
} else {
break;
}
}
// Store the batch index for marking completion
let batch_idx = idx;
let ui_clone = ui.clone();
// Start processing with a small delay so the UI updates
glib::timeout_add_local_once(std::time::Duration::from_millis(100), move || {
if let Some(root) = ui_clone.nav_view.root()
&& let Some(win) = root.downcast_ref::<adw::ApplicationWindow>()
{
run_processing(win, &ui_clone);
}
});
// We need to mark the batch as completed when processing finishes.
// This is handled in show_results via the queue check.
let _ = batch_idx;
true
}
/// Mark the currently-processing batch in the queue as completed or failed.
fn mark_current_queue_batch(ui: &WizardUi, success: bool, error_msg: Option<&str>) {
let mut queue = ui.state.batch_queue.borrow_mut();
if let Some(batch) = queue.batches.iter_mut().find(|b| b.status == BatchStatus::Processing) {
batch.status = if success {
BatchStatus::Completed
} else {
BatchStatus::Failed(error_msg.unwrap_or("Unknown error").to_string())
};
}
drop(queue);
refresh_queue_list(ui);
}