fix(backend): avoid heavy ticket payloads in list commands

This commit is contained in:
thibaud-lclr 2026-04-20 17:54:23 +02:00
parent 64c1dd1789
commit 9de295dfe8
3 changed files with 41 additions and 3 deletions

View file

@ -184,7 +184,7 @@ pub fn get_queue_status(
.lock() .lock()
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
let tickets = ProcessedTicket::list_by_project(&db, &project_id)?; let tickets = ProcessedTicket::list_by_project_summary(&db, &project_id)?;
Ok(tickets) Ok(tickets)
} }
@ -246,7 +246,7 @@ pub fn get_runtime_activity(
.db .db
.lock() .lock()
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
let project_tickets = ProcessedTicket::list_by_project(&db, &project_id)?; let project_tickets = ProcessedTicket::list_by_project_summary(&db, &project_id)?;
let mut agents_by_ticket_id: HashMap<String, RuntimeActiveAgent> = HashMap::new(); let mut agents_by_ticket_id: HashMap<String, RuntimeActiveAgent> = HashMap::new();
for ticket in &project_tickets { for ticket in &project_tickets {

View file

@ -165,6 +165,6 @@ pub fn list_processed_tickets(
.lock() .lock()
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
let tickets = ProcessedTicket::list_by_project(&db, &project_id)?; let tickets = ProcessedTicket::list_by_project_summary(&db, &project_id)?;
Ok(tickets) Ok(tickets)
} }

View file

@ -52,6 +52,9 @@ fn from_row(row: &rusqlite::Row) -> rusqlite::Result<ProcessedTicket> {
const SELECT_ALL_COLS: &str = "SELECT id, tracker_id, project_id, source, source_ref, \ const SELECT_ALL_COLS: &str = "SELECT id, tracker_id, project_id, source, source_ref, \
artifact_id, artifact_title, artifact_data, status, analyst_report, developer_report, \ artifact_id, artifact_title, artifact_data, status, analyst_report, developer_report, \
worktree_path, branch_name, detected_at, processed_at FROM processed_tickets"; worktree_path, branch_name, detected_at, processed_at FROM processed_tickets";
const SELECT_SUMMARY_COLS: &str = "SELECT id, tracker_id, project_id, source, source_ref, \
artifact_id, artifact_title, '' AS artifact_data, status, analyst_report, developer_report, \
worktree_path, branch_name, detected_at, processed_at FROM processed_tickets";
impl ProcessedTicket { impl ProcessedTicket {
/// Atomically insert a new ticket keyed by (tracker_id, artifact_id). /// Atomically insert a new ticket keyed by (tracker_id, artifact_id).
@ -168,6 +171,7 @@ impl ProcessedTicket {
rows.collect() rows.collect()
} }
#[allow(dead_code)]
pub fn list_by_project(conn: &Connection, project_id: &str) -> Result<Vec<ProcessedTicket>> { pub fn list_by_project(conn: &Connection, project_id: &str) -> Result<Vec<ProcessedTicket>> {
let sql = format!( let sql = format!(
"{} WHERE project_id = ?1 ORDER BY detected_at DESC", "{} WHERE project_id = ?1 ORDER BY detected_at DESC",
@ -178,6 +182,19 @@ impl ProcessedTicket {
rows.collect() rows.collect()
} }
pub fn list_by_project_summary(
conn: &Connection,
project_id: &str,
) -> Result<Vec<ProcessedTicket>> {
let sql = format!(
"{} WHERE project_id = ?1 ORDER BY detected_at DESC",
SELECT_SUMMARY_COLS
);
let mut stmt = conn.prepare(&sql)?;
let rows = stmt.query_map(params![project_id], from_row)?;
rows.collect()
}
pub fn get_project_throughput_stats( pub fn get_project_throughput_stats(
conn: &Connection, conn: &Connection,
project_id: &str, project_id: &str,
@ -801,4 +818,25 @@ mod tests {
assert!(tickets.iter().any(|ticket| ticket.source == "graylog")); assert!(tickets.iter().any(|ticket| ticket.source == "graylog"));
assert!(tickets.iter().any(|ticket| ticket.source == "tuleap")); assert!(tickets.iter().any(|ticket| ticket.source == "tuleap"));
} }
#[test]
fn test_list_by_project_summary_omits_artifact_payload() {
let (conn, project_id, tracker_id) = setup();
ProcessedTicket::insert_if_new(
&conn,
&project_id,
&tracker_id,
999,
"Large payload ticket",
&"x".repeat(10_000),
)
.expect("insert should succeed");
let tickets = ProcessedTicket::list_by_project_summary(&conn, &project_id)
.expect("summary list should succeed");
assert!(!tickets.is_empty());
assert!(tickets.iter().all(|ticket| ticket.artifact_data.is_empty()));
}
} }