001-video-wall #52
79
src/main.rs
79
src/main.rs
@@ -750,6 +750,20 @@ async fn get_preview_status(
|
|||||||
|
|
||||||
for path in &body.paths {
|
for path in &body.paths {
|
||||||
if let Some(clip) = clip_map.get(path) {
|
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 {
|
items.push(PreviewStatusItem {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
status: clip.status.clone(),
|
status: clip.status.clone(),
|
||||||
@@ -1655,7 +1669,8 @@ fn process_new_files(
|
|||||||
let needs_preview = match status {
|
let needs_preview = match status {
|
||||||
None => true, // No record at all
|
None => true, // No record at all
|
||||||
Some("failed") => true, // Retry failed
|
Some("failed") => true, // Retry failed
|
||||||
_ => false, // pending, processing, or complete
|
Some("pending") => true, // Stale pending from previous run
|
||||||
|
_ => false, // processing or complete
|
||||||
};
|
};
|
||||||
|
|
||||||
if needs_preview {
|
if needs_preview {
|
||||||
@@ -1851,4 +1866,66 @@ mod tests {
|
|||||||
assert_eq!(previews[2]["path"], "c.mp4");
|
assert_eq!(previews[2]["path"], "c.mp4");
|
||||||
assert_eq!(previews[2]["status"], "pending");
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user