From 7a5a71471eb3ba5c94faba83d243b70dfae9b6c3 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 23 May 2026 21:25:57 -0400 Subject: [PATCH] fix(scan): auto-finalize empty scans + system_stats picks running batch with actual work Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/app/api/settings.py | 16 ++++++++++++++-- backend/app/tasks/scan.py | 9 +++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/backend/app/api/settings.py b/backend/app/api/settings.py index 15c52e9..145890e 100644 --- a/backend/app/api/settings.py +++ b/backend/app/api/settings.py @@ -141,11 +141,23 @@ async def system_stats(): ).all() integrity_counts = {row[0]: row[1] for row in integrity_rows} - # Active batch (most recent running) + # Active batch = running batch that still has outstanding work. + # Plain "most recent running" picks a freshly-created scan that + # enqueued zero new files and hides the older batch that's + # actually being processed; the EXISTS clause filters those + # empty batches out. active_batch_row = ( await session.execute( select(ImportBatch) - .where(ImportBatch.status == "running") + .where( + ImportBatch.status == "running", + select(ImportTask.id) + .where( + ImportTask.batch_id == ImportBatch.id, + ImportTask.status.in_(["pending", "queued", "processing"]), + ) + .exists(), + ) .order_by(ImportBatch.started_at.desc()) .limit(1) ) diff --git a/backend/app/tasks/scan.py b/backend/app/tasks/scan.py index c4581f7..6aacde0 100644 --- a/backend/app/tasks/scan.py +++ b/backend/app/tasks/scan.py @@ -95,6 +95,15 @@ def scan_directory(self, triggered_by: str = "manual", files_seen += 1 batch.total_files = files_seen + # If the walk enqueued nothing (every file was already on a + # non-failed ImportTask from a prior scan), there's no + # import_media_file message that would ever flip this batch to + # 'complete' — finalize it now so the active-batch query in + # /api/system/stats doesn't get stuck reporting all-zero + # counters from an empty scan. + if files_seen == 0: + batch.status = "complete" + batch.finished_at = datetime.now(UTC) session.commit() # Now enqueue import_media_file for each pending task.