feat: auto-invalidate cache when installed node set changes

Fingerprints NODE_CLASS_MAPPINGS; on the first object_info request after a
restart, drops the cached object_info if a node was installed/updated/enabled/
removed, so new nodes appear without a manual refresh. First run (no stored
signature) does not invalidate. Unit-tested.

Also documents that the pack has no deps and does not interfere with other
nodes' installs/updates or their own routes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 23:16:39 +02:00
parent a8d8b3792c
commit 4a1c2f3a99
2 changed files with 64 additions and 0 deletions
+49
View File
@@ -26,6 +26,7 @@ import os
import gzip
import json
import time
import hashlib
import logging
import threading
@@ -45,6 +46,7 @@ _CACHE_DIR = os.path.join(os.path.dirname(__file__), "cache")
_RAW_PATH = os.path.join(_CACHE_DIR, "object_info.json")
_GZ_PATH = os.path.join(_CACHE_DIR, "object_info.json.gz")
_SNAP_PATH = os.path.join(_CACHE_DIR, "scan_snapshot.json")
_SIG_PATH = os.path.join(_CACHE_DIR, "node_signature.txt")
_OBJECT_INFO_PATHS = ("/object_info", "/api/object_info")
_GZIP_LEVEL = 5
@@ -297,6 +299,51 @@ def register_files(folder_name, rel_paths):
return {"added": added, "skipped": skipped, "folder": folder_name, "files": len(filtered)}
# --------------------------------------------------------------------------- #
# Auto-invalidate when installed nodes change (install / update / enable / remove)
# --------------------------------------------------------------------------- #
_sig_checked = False
def _current_node_signature():
"""A cheap fingerprint of the available node set. Changes when a node is
installed, removed, enabled or disabled."""
try:
import nodes
keys = sorted(nodes.NODE_CLASS_MAPPINGS.keys())
except Exception:
return None
h = hashlib.sha1()
for k in keys:
h.update(k.encode("utf-8", "replace"))
h.update(b"\x00")
return f"{len(keys)}:{h.hexdigest()}"
def _check_node_signature():
"""Drop the cached object_info if the node set changed since last run, so
newly installed/updated nodes show up without a manual refresh."""
global _sig_checked
_sig_checked = True
try:
cur = _current_node_signature()
if cur is None:
return
old = None
if os.path.exists(_SIG_PATH):
with open(_SIG_PATH) as f:
old = f.read().strip()
if old is not None and old != cur:
log.info("Tenaciousload: installed node set changed -> invalidating object_info cache")
invalidate_object_info_cache()
if old != cur:
os.makedirs(_CACHE_DIR, exist_ok=True)
with open(_SIG_PATH, "w") as f:
f.write(cur)
except Exception as e: # pragma: no cover
log.warning("Tenaciousload: node signature check failed: %s", e)
# --------------------------------------------------------------------------- #
# object_info caching middleware
# --------------------------------------------------------------------------- #
@@ -324,6 +371,8 @@ async def _object_info_cache_mw(request, handler):
global _disk_loaded
if not _disk_loaded:
_load_from_disk()
if not _sig_checked:
_check_node_signature() # auto-drop cache if nodes were installed/updated
if "nocache" not in request.query and _mem["raw"] is not None:
return _serve_cached(request)