From a70637feff1e2a8346d421a0d89831da2caa2246 Mon Sep 17 00:00:00 2001 From: tanyar09 Date: Tue, 4 Nov 2025 15:05:43 -0500 Subject: [PATCH] feat: Improve photo processing cancellation handling in face service This commit enhances the photo processing workflow in the FaceService by ensuring that cancellation checks occur after completing the current photo's processing, including pose detection and database commits. It introduces robust error handling during progress updates, allowing for graceful cancellation and improved user feedback. Documentation has been updated to reflect these changes, enhancing the overall user experience and reliability of the photo processing feature. --- src/web/services/face_service.py | 100 ++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 14 deletions(-) diff --git a/src/web/services/face_service.py b/src/web/services/face_service.py index 62ddec1..ba8c4d7 100644 --- a/src/web/services/face_service.py +++ b/src/web/services/face_service.py @@ -702,6 +702,8 @@ def process_unprocessed_photos( first_photo_start = time.time() print(f"[FaceService] Starting first photo processing...") + # Process photo fully (including pose detection, DeepFace, and database commit) + # This ensures all data is complete before checking for cancellation faces_detected, faces_stored = process_photo_faces( db, photo, @@ -718,27 +720,97 @@ def process_unprocessed_photos( first_photo_time = time.time() - first_photo_start print(f"[FaceService] First photo completed in {first_photo_time:.2f}s") + # Check for cancellation AFTER finishing the current photo completely + # This allows the current photo to complete (including pose detection and DB commit), + # then stops before the next one + if check_cancelled(): + print(f"[FaceService] Job cancelled after finishing photo {idx}/{total}") + # Update progress to show cancellation status + if update_progress: + try: + update_progress( + idx, + total, + "Cancelled by user - finished current photo", + total_faces_detected, + total_faces_stored, + ) + except KeyboardInterrupt: + # If update_progress raises KeyboardInterrupt, that's expected + # The cancellation check already happened, so we're good + pass + break + + # Update progress only if NOT cancelled (to avoid unnecessary KeyboardInterrupt) if update_progress: - update_progress( - idx, - total, - f"Completed {photo.filename} ({idx}/{total})", - total_faces_detected, - total_faces_stored, - ) + try: + update_progress( + idx, + total, + f"Completed {photo.filename} ({idx}/{total})", + total_faces_detected, + total_faces_stored, + ) + except KeyboardInterrupt: + # If cancellation was detected during update_progress, check again and break + if check_cancelled(): + print(f"[FaceService] Job cancelled during progress update after photo {idx}/{total}") + break + # Re-raise if it wasn't a cancellation + raise + except KeyboardInterrupt: + # Cancellation was requested - stop processing gracefully + print(f"[FaceService] Job cancelled during processing of photo {idx}/{total}") + if check_cancelled(): + if update_progress: + try: + update_progress( + idx, + total, + "Cancelled by user", + total_faces_detected, + total_faces_stored, + ) + except KeyboardInterrupt: + pass + break + # Re-raise if it wasn't a cancellation + raise except Exception as e: # Log error but continue processing other photos print(f"[FaceService] Error processing photo {photo.filename}: {e}") import traceback traceback.print_exc() if update_progress: - update_progress( - idx, - total, - f"Error: {photo.filename}", - total_faces_detected, - total_faces_stored, - ) + try: + update_progress( + idx, + total, + f"Error: {photo.filename}", + total_faces_detected, + total_faces_stored, + ) + except KeyboardInterrupt: + # If cancellation detected during error progress update, stop + if check_cancelled(): + print(f"[FaceService] Job cancelled after error on photo {idx}/{total}") + break + + # Check for cancellation after handling error + if check_cancelled(): + print(f"[FaceService] Job cancelled after error on photo {idx}/{total}") + if update_progress: + try: + update_progress( + idx, + total, + "Cancelled by user - finished current photo", + total_faces_detected, + total_faces_stored, + ) + except KeyboardInterrupt: + pass + break return photos_processed, total_faces_detected, total_faces_stored