fix: diagnostics and monitor respect config, singleton lifecycle (#132) (#133)

* fix: diagnostics, backup, and restore now respect config.json db path (#132)

* test: add regression tests for config-aware diagnostics and backup (#132)

* fix(test): use fresh event loop to avoid aiohttp test pollution

* fix: don't kill singleton image monitor when node instance is garbage collected

The __del__ method was calling stop_monitoring() on the shared singleton
ImageMonitor, killing it for ALL nodes whenever any single node instance
was garbage collected between workflow runs. This caused the monitor to
restart on every execution and miss image save events due to race conditions.

* test: add regression tests for image monitor singleton lifecycle

Ensures cleanup/del never stops the shared monitor, singleton is
thread-safe, and observer survives across node instance lifecycles.

* style: address PR review — log suppressed exceptions, remove unused imports
This commit is contained in:
Vito
2026-04-03 06:22:55 -07:00
committed by GitHub
parent 7f45bc6df7
commit 2cf9f42e73
5 changed files with 445 additions and 40 deletions
+52 -22
View File
@@ -58,15 +58,34 @@ class GalleryDiagnostics:
- Additional data specific to the diagnostic
"""
def __init__(self, db_path: str = "prompts.db"):
def __init__(self, db_path: str = None):
"""Initialize the diagnostics system.
Args:
db_path: Path to the SQLite database file to diagnose
db_path: Path to the SQLite database file to diagnose.
If None, resolves from config.json or defaults to
prompts.db in the extension root.
"""
if db_path is None:
db_path = self._resolve_db_path()
self.db_path = db_path
self.logger = get_logger("prompt_manager.diagnostics")
@staticmethod
def _resolve_db_path() -> str:
"""Resolve database path from config, matching PromptDatabase logic."""
extension_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
try:
from py.config import PromptManagerConfig
db_path = PromptManagerConfig.DEFAULT_DB_PATH
except Exception:
db_path = "prompts.db"
if not os.path.isabs(db_path):
db_path = os.path.join(extension_root, db_path)
return db_path
def run_full_diagnostic(self) -> Dict[str, Any]:
"""Run a complete diagnostic check.
@@ -268,23 +287,10 @@ class GalleryDiagnostics:
output_dirs = []
# Try to detect ComfyUI output directories
potential_dirs = [
"output",
"../output",
"../../output",
"ComfyUI/output",
"../ComfyUI/output",
"../../ComfyUI/output",
]
for dir_path in potential_dirs:
abs_path = os.path.abspath(dir_path)
if os.path.exists(abs_path):
def _add_dir(abs_path, source):
if abs_path not in output_dirs:
output_dirs.append(abs_path)
self.logger.info(f" [DIR] Found output dir: {abs_path}")
# Count images in this directory
self.logger.info(f" [DIR] {source}: {abs_path}")
try:
image_files = []
for ext in [".png", ".jpg", ".jpeg", ".webp"]:
@@ -293,17 +299,41 @@ class GalleryDiagnostics:
except Exception as e:
self.logger.error(f" [FAIL] Error scanning: {e}")
# Try ComfyUI's folder_paths
# Check user-configured gallery directories from config.json
try:
from py.config import GalleryConfig
for cfg_dir in GalleryConfig.MONITORING_DIRECTORIES:
abs_path = os.path.abspath(cfg_dir)
if os.path.exists(abs_path):
_add_dir(abs_path, "Configured directory")
except Exception as e:
self.logger.debug(f" [NOTE] Could not load gallery config: {e}")
# Check ComfyUI's own output directory (respects --output-directory)
try:
import folder_paths
comfyui_output = folder_paths.get_output_directory()
if comfyui_output and comfyui_output not in output_dirs:
output_dirs.append(comfyui_output)
self.logger.info(f" [DIR] ComfyUI output dir: {comfyui_output}")
if comfyui_output and os.path.exists(comfyui_output):
_add_dir(os.path.abspath(comfyui_output), "ComfyUI output dir")
except ImportError:
self.logger.warning(" [WARN] ComfyUI folder_paths not available")
# Fallback: check common relative paths
if not output_dirs:
for dir_path in [
"output",
"../output",
"../../output",
"ComfyUI/output",
"../ComfyUI/output",
"../../ComfyUI/output",
]:
abs_path = os.path.abspath(dir_path)
if os.path.exists(abs_path):
_add_dir(abs_path, "Found output dir")
return {
"status": "ok" if output_dirs else "warning",
"message": "No output directories found" if not output_dirs else None,