Ensure we re-queue pending/failed records

This commit is contained in:
Cameron
2026-02-26 10:42:20 -05:00
parent 32ece84209
commit 36612444c5

View File

@@ -750,6 +750,20 @@ async fn get_preview_status(
for path in &body.paths {
if let Some(clip) = clip_map.get(path) {
// Re-queue generation for stale pending/failed records
if clip.status == "pending" || clip.status == "failed" {
let full_path = format!(
"{}/{}",
app_state.base_path.trim_end_matches(['/', '\\']),
path.trim_start_matches(['/', '\\'])
);
app_state
.preview_clip_generator
.do_send(GeneratePreviewClipMessage {
video_path: full_path,
});
}
items.push(PreviewStatusItem {
path: path.clone(),
status: clip.status.clone(),
@@ -1653,9 +1667,10 @@ fn process_new_files(
for (full_path, relative_path) in &video_files {
let status = existing_previews.get(relative_path).map(|s| s.as_str());
let needs_preview = match status {
None => true, // No record at all
Some("failed") => true, // Retry failed
_ => false, // pending, processing, or complete
None => true, // No record at all
Some("failed") => true, // Retry failed
Some("pending") => true, // Stale pending from previous run
_ => false, // processing or complete
};
if needs_preview {
@@ -1851,4 +1866,66 @@ mod tests {
assert_eq!(previews[2]["path"], "c.mp4");
assert_eq!(previews[2]["status"], "pending");
}
/// Verifies that the status endpoint re-queues generation for stale
/// "pending" and "failed" records (e.g., after a server restart or
/// when clip files were deleted). The do_send to the actor exercises
/// the re-queue code path; the actor runs against temp dirs so it
/// won't panic.
#[actix_rt::test]
async fn test_get_preview_status_requeues_pending_and_failed() {
let mut dao = TestPreviewDao::new();
let ctx = opentelemetry::Context::new();
// Simulate stale records left from a previous server run
dao.insert_preview(&ctx, "stale/pending.mp4", "pending")
.unwrap();
dao.insert_preview(&ctx, "stale/failed.mp4", "pending")
.unwrap();
dao.update_status(
&ctx,
"stale/failed.mp4",
"failed",
None,
None,
Some("ffmpeg error"),
)
.unwrap();
let preview_dao = make_preview_dao(dao);
let app_state = Data::new(AppState::test_state());
let token = make_token();
let app = actix_web::test::init_service(
App::new()
.service(get_preview_status)
.app_data(app_state)
.app_data(preview_dao),
)
.await;
let req = actix_web::test::TestRequest::post()
.uri("/video/preview/status")
.insert_header(("Authorization", format!("Bearer {}", token)))
.set_json(serde_json::json!({
"paths": ["stale/pending.mp4", "stale/failed.mp4"]
}))
.to_request();
let resp = actix_web::test::call_service(&app, req).await;
assert_eq!(resp.status(), 200);
let body: serde_json::Value = actix_web::test::read_body_json(resp).await;
let previews = body["previews"].as_array().unwrap();
assert_eq!(previews.len(), 2);
// Both records are returned with their current status
assert_eq!(previews[0]["path"], "stale/pending.mp4");
assert_eq!(previews[0]["status"], "pending");
assert!(previews[0].get("preview_url").is_none());
assert_eq!(previews[1]["path"], "stale/failed.mp4");
assert_eq!(previews[1]["status"], "failed");
assert!(previews[1].get("preview_url").is_none());
}
}