fix(indexer): recover cleanly from indexing failures

Move sqlite-vec embedding deletions outside the image transaction to avoid transactional virtual-table failures. Emit a terminal indexing progress event on errors so the frontend reloads partial state and clears its active scan state.
This commit is contained in:
2026-06-06 19:51:44 +01:00
parent d7595703de
commit 6824dcffb3
2 changed files with 19 additions and 4 deletions
+6 -2
View File
@@ -901,10 +901,14 @@ pub fn get_folder_media_index(conn: &Connection, folder_id: i64) -> Result<Vec<I
}
pub fn delete_images_by_ids(conn: &Connection, image_ids: &[i64]) -> Result<()> {
// Delete from sqlite-vec virtual tables outside the transaction — sqlite-vec
// has known issues with transactional DML in early versions.
for image_id in image_ids {
vector::delete_embedding(conn, *image_id)?;
vector::delete_caption_embedding(conn, *image_id)?;
}
let tx = conn.unchecked_transaction()?;
for image_id in image_ids {
vector::delete_embedding(&tx, *image_id)?;
vector::delete_caption_embedding(&tx, *image_id)?;
tx.execute("DELETE FROM images WHERE id = ?1", [image_id])?;
}
tx.commit()?;
+13 -2
View File
@@ -150,8 +150,19 @@ pub fn index_folder(app: AppHandle, pool: DbPool, folder_id: i64, folder_path: P
let storage_profile = detect_storage_profile(&folder_path);
set_folder_storage_profile(folder_id, RuntimeAdaptiveProfile::new(storage_profile));
set_folder_indexing_state(folder_id, true);
if let Err(error) = do_index(app, pool, folder_id, folder_path) {
eprintln!("Indexing error: {}", error);
if let Err(error) = do_index(app.clone(), pool, folder_id, folder_path) {
eprintln!("Indexing error for folder {}: {}", folder_id, error);
// Always emit done so the frontend reloads and recovers from partial state.
emit_progress(
&app,
&IndexProgress {
folder_id,
total: 0,
indexed: 0,
current_file: String::new(),
done: true,
},
);
}
set_folder_indexing_state(folder_id, false);
});