feat: verification agent for processor output validation
- New src/verification/ module: verify_output() checks JSON structure/completeness per processor type
- Worker: after processor succeeds, verification agent gates the result
- Passed -> mark completed + cleanup_temp_files (remove .tmp/.partial/.err/timestamp backups)
- Failed -> mark failed with verification details, preserve files for inspection
- cleanup_temp_files() keeps only the canonical {uuid}.{proc}.json
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use anyhow::{Context, Result};
|
||||
use libc;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, RwLock};
|
||||
@@ -229,39 +230,89 @@ impl ProcessorPool {
|
||||
|
||||
match result {
|
||||
Ok(output) => {
|
||||
info!(
|
||||
"Processor {} completed for job {} ({} chunks, {} frames)",
|
||||
processor_name, job.uuid, output.chunks_produced, output.frames_processed
|
||||
// 驗收 agent 檢查產出內容
|
||||
let verification = crate::verification::verifier::verify_output(
|
||||
&processor_type,
|
||||
&job.uuid,
|
||||
);
|
||||
if let Err(e) = db
|
||||
.update_processor_result_with_stats(
|
||||
processor_result_id,
|
||||
ProcessorJobStatus::Completed,
|
||||
None,
|
||||
Some(&output.data),
|
||||
output.chunks_produced,
|
||||
output.frames_processed,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to update processor result to completed: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = redis
|
||||
.update_worker_processor_status(
|
||||
if verification.passed {
|
||||
info!(
|
||||
"Processor {} completed and verified for job {} ({} chunks, {} frames)",
|
||||
processor_name, job.uuid, output.chunks_produced, output.frames_processed
|
||||
);
|
||||
|
||||
// 清理暫存備份
|
||||
crate::verification::verifier::cleanup_temp_files(
|
||||
&processor_type,
|
||||
&job.uuid,
|
||||
&processor_name,
|
||||
"completed",
|
||||
None,
|
||||
output.frames_processed,
|
||||
output.chunks_produced,
|
||||
output.total_frames,
|
||||
output.retry_count,
|
||||
output.pid,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to update Redis processor status: {}", e);
|
||||
);
|
||||
|
||||
if let Err(e) = db
|
||||
.update_processor_result_with_stats(
|
||||
processor_result_id,
|
||||
ProcessorJobStatus::Completed,
|
||||
None,
|
||||
Some(&output.data),
|
||||
output.chunks_produced,
|
||||
output.frames_processed,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to update processor result to completed: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = redis
|
||||
.update_worker_processor_status(
|
||||
&job.uuid,
|
||||
&processor_name,
|
||||
"completed",
|
||||
None,
|
||||
output.frames_processed,
|
||||
output.chunks_produced,
|
||||
output.total_frames,
|
||||
output.retry_count,
|
||||
output.pid,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to update Redis processor status: {}", e);
|
||||
}
|
||||
} else {
|
||||
error!(
|
||||
"Processor {} output failed verification for job {}: {:?}",
|
||||
processor_name, job.uuid, verification.details
|
||||
);
|
||||
if let Err(db_err) = db
|
||||
.update_processor_result_with_stats(
|
||||
processor_result_id,
|
||||
ProcessorJobStatus::Failed,
|
||||
Some(&format!("verification failed: {:?}", verification.details)),
|
||||
None,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to update processor result to failed: {}", db_err);
|
||||
}
|
||||
|
||||
if let Err(redis_err) = redis
|
||||
.update_worker_processor_status(
|
||||
&job.uuid,
|
||||
&processor_name,
|
||||
"failed",
|
||||
Some(&format!("verification failed: {:?}", verification.details)),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Failed to update Redis processor status: {}", redis_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user