fix(images): a monitor invalidation rebuilds only the new files' values

The image monitor invalidates the gallery whenever it sees a new file,
and that dropped every derived workspace value, so the next request paid
a full cold build. Invalidation now keeps the per-file values and drops
only the sort orders; the rescan reuses every unchanged file and builds
only new or changed ones. A gallery-roots change still drops everything.
This commit is contained in:
Vito Sansevero
2026-10-19 23:05:34 -07:00
parent b6158b95bf
commit d2b5b25a42
4 changed files with 20 additions and 10 deletions
+8 -2
View File
@@ -353,12 +353,18 @@ class PromptManagerAPI(
"""Invalidate the cached gallery file listing.
Called by the image monitor when new files are detected. The workspace
values derived from a scan are dropped with it.
keeps its per-file values, so the next request rebuilds only new or
changed files (see ImageRoutesMixin._workspace_listed); its sort orders
are dropped, as the rescan replaces them anyway.
"""
self._gallery_cache = {}
self._workspace_listed_cache = {}
self._workspace_order_cache = {}
def reset_gallery_roots_cache(self):
"""Drop every cached listing and derived workspace value (roots changed)."""
self.invalidate_gallery_cache()
self._workspace_listed_cache = {}
def add_routes(self, routes):
"""Register all API routes with the ComfyUI server.
+1 -1
View File
@@ -897,7 +897,7 @@ class AdminRoutesMixin:
return False
GalleryConfig.MONITORING_DIRECTORIES = roots
self._cached_output_dir = None
self.invalidate_gallery_cache()
self.reset_gallery_roots_cache()
return True
def _persist_settings(self):
+1 -1
View File
@@ -990,7 +990,7 @@ class ImageRoutesMixin:
The gallery cache hands out the same list object until it rescans.
A rescan reuses the value of every unchanged ``(path, mtime)`` and,
when nothing changed, the previous list itself, so the cached sort
orders stay valid. invalidate_gallery_cache drops these values.
orders stay valid. Only a gallery-roots change drops these values.
"""
key = (index, str(root))
cached = self._workspace_listed_cache.get(key)
+10 -6
View File
@@ -1200,14 +1200,18 @@ class TestWorkspaceImages(ImageAPITestCase):
self.assertEqual(built, [added[0]])
self.assertEqual(data["total"], len(listed))
self.assertEqual(data["images"][0]["filename"], "new.png")
# Invalidation (the monitor saw new files) and a roots change drop
# every derived value.
# The monitor invalidates the gallery when it sees a new file: the
# next request rebuilds only that file's values, and search finds it.
self.api.invalidate_gallery_cache()
self.assertEqual(self.api._workspace_listed_cache, {})
self.assertEqual(self.api._workspace_order_cache, {})
self.assertNotEqual(self.api._workspace_listed_cache, {})
monitored = (self.output_dir / "day-01" / "monitored.png", 9_999_999.5)
scans.append([monitored, *scans[-1]])
built.clear()
response, data = await self.get(limit=10)
self.assertEqual(len(built), len(listed))
response, data = await self.get(limit=10, q="monitored")
self.assertEqual(response.status, 200)
self.assertEqual(built, [monitored[0]])
self.assertEqual(self._names(data), ["monitored.png"])
# A roots change drops every derived value.
with patch("py.config.GalleryConfig.MONITORING_DIRECTORIES", []):
self.assertTrue(self.api._apply_gallery_roots([str(self.output_dir)]))
self.assertEqual(self.api._workspace_listed_cache, {})