feat: async insight generation with SQLite job tracking
- Add insight_generation_jobs table migration and DAO - Implement job lifecycle: create_or_get_active, complete, fail, cancel - Refactor POST /insights/generate and /agentic to async spawn with timeout - Add GET /insights/generation/status endpoint with job_id and file_path lookup - Use String for enum fields in Diesel models to avoid private Bound type - Add from_str() helpers on InsightJobStatus and InsightGenerationType - Fix update_training_messages to return Result<usize, DbError> - 7/7 DAO unit tests passing
This commit is contained in:
+35
-3
@@ -107,6 +107,11 @@ impl InsightChatService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Accessor for the insight DAO (used by async job completion).
|
||||
pub fn insight_dao(&self) -> &Arc<Mutex<Box<dyn InsightDao>>> {
|
||||
&self.insight_dao
|
||||
}
|
||||
|
||||
/// Load the rendered transcript for chat-UI display. Filters internal
|
||||
/// scaffolding (system message, tool turns, tool-dispatch-only assistant
|
||||
/// messages) and drops base64 images from user turns to keep payloads
|
||||
@@ -522,8 +527,17 @@ impl InsightChatService {
|
||||
} else {
|
||||
let cx = opentelemetry::Context::new();
|
||||
let mut dao = self.insight_dao.lock().expect("Unable to lock InsightDao");
|
||||
dao.update_training_messages(&cx, req.library_id, &normalized, &json)
|
||||
let rows = dao
|
||||
.update_training_messages(&cx, req.library_id, &normalized, &json)
|
||||
.map_err(|e| anyhow!("failed to persist chat history: {:?}", e))?;
|
||||
if rows == 0 {
|
||||
log::warn!(
|
||||
"update_training_messages updated 0 rows for {} (lib {}), \
|
||||
concurrent regenerate likely flipped is_current",
|
||||
normalized,
|
||||
req.library_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ChatTurnResult {
|
||||
@@ -590,8 +604,17 @@ impl InsightChatService {
|
||||
|
||||
let cx = opentelemetry::Context::new();
|
||||
let mut dao = self.insight_dao.lock().expect("Unable to lock InsightDao");
|
||||
dao.update_training_messages(&cx, library_id, &normalized, &json)
|
||||
let rows = dao
|
||||
.update_training_messages(&cx, library_id, &normalized, &json)
|
||||
.map_err(|e| anyhow!("failed to persist truncated history: {:?}", e))?;
|
||||
if rows == 0 {
|
||||
log::warn!(
|
||||
"update_training_messages (rewind) updated 0 rows for {} (lib {}), \
|
||||
concurrent regenerate likely flipped is_current",
|
||||
normalized,
|
||||
library_id
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -851,8 +874,17 @@ impl InsightChatService {
|
||||
} else {
|
||||
let cx = opentelemetry::Context::new();
|
||||
let mut dao = self.insight_dao.lock().expect("Unable to lock InsightDao");
|
||||
dao.update_training_messages(&cx, req.library_id, &normalized, &json)
|
||||
let rows = dao
|
||||
.update_training_messages(&cx, req.library_id, &normalized, &json)
|
||||
.map_err(|e| anyhow!("failed to persist chat history: {:?}", e))?;
|
||||
if rows == 0 {
|
||||
log::warn!(
|
||||
"update_training_messages (stream) updated 0 rows for {} (lib {}), \
|
||||
concurrent regenerate likely flipped is_current",
|
||||
normalized,
|
||||
req.library_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let _ = tx
|
||||
|
||||
Reference in New Issue
Block a user