f
This commit is contained in:
@@ -16,6 +16,7 @@ import logging
|
||||
import subprocess
|
||||
import shutil
|
||||
import time
|
||||
import os
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime
|
||||
from pathlib import Path, PurePosixPath
|
||||
@@ -23,12 +24,18 @@ from threading import RLock
|
||||
from typing import Optional, Dict, Any, List, Tuple, Set
|
||||
|
||||
from SYS.utils import sha256_file, expand_path
|
||||
from SYS.logger import debug as mm_debug
|
||||
from SYS.logger import debug as _debug
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
WORKER_LOG_MAX_ENTRIES = 50 # Reduced from 99 to keep log size down
|
||||
MAX_FINISHED_WORKERS = 100 # Only keep 100 finished workers globally
|
||||
|
||||
# Wrapper: only emit folder DB diagnostics when MM_DEBUG=1
|
||||
def mm_debug(*args, **kwargs):
|
||||
if not os.environ.get("MM_DEBUG"):
|
||||
return
|
||||
_debug(*args, **kwargs)
|
||||
|
||||
# Helper: decorate DB write methods to retry transient SQLITE 'database is locked' errors
|
||||
def _db_retry(max_attempts: int = 6, base_sleep: float = 0.1):
|
||||
def _decorator(func):
|
||||
|
||||
4
CLI.py
4
CLI.py
@@ -823,7 +823,9 @@ class CmdletIntrospection:
|
||||
normalized_arg = (arg_name or "").lstrip("-").strip().lower()
|
||||
|
||||
if normalized_arg in ("storage", "store"):
|
||||
backends = cls.store_choices(config, force=force)
|
||||
# Use cached/lightweight names for completions to avoid instantiating backends
|
||||
# (instantiating backends may perform initialization such as opening folder DBs).
|
||||
backends = cls.store_choices(config, force=False)
|
||||
if backends:
|
||||
return backends
|
||||
|
||||
|
||||
@@ -222,19 +222,27 @@ class SharedArgs:
|
||||
if not force and hasattr(SharedArgs, "_cached_available_stores"):
|
||||
return SharedArgs._cached_available_stores or []
|
||||
|
||||
# Refresh the cache
|
||||
SharedArgs._refresh_store_choices_cache(config)
|
||||
# Refresh the cache. When not forcing, prefer a lightweight configured-name
|
||||
# pass to avoid instantiating backends (which may perform work such as opening DBs).
|
||||
if not force:
|
||||
SharedArgs._refresh_store_choices_cache(config, skip_instantiation=True)
|
||||
else:
|
||||
SharedArgs._refresh_store_choices_cache(config, skip_instantiation=False)
|
||||
return SharedArgs._cached_available_stores or []
|
||||
|
||||
@staticmethod
|
||||
def _refresh_store_choices_cache(config: Optional[Dict[str, Any]] = None) -> None:
|
||||
def _refresh_store_choices_cache(config: Optional[Dict[str, Any]] = None, skip_instantiation: bool = False) -> None:
|
||||
"""Refresh the cached store choices list. Should be called once at startup.
|
||||
|
||||
This performs the actual StoreRegistry initialization check and caches the result.
|
||||
Subsequent calls to get_store_choices() will use this cache.
|
||||
This performs a lightweight pass first (reads configured names only, without
|
||||
instantiating backend classes) to avoid side-effects during autocompletion or
|
||||
other quick lookups. When `skip_instantiation` is False, the function will
|
||||
attempt a full StoreRegistry initialization to filter out backends that failed
|
||||
to initialize properly.
|
||||
|
||||
Args:
|
||||
config: Config dict. If not provided, will try to load from config module.
|
||||
skip_instantiation: When True, do not instantiate backend classes; use a lightweight list only.
|
||||
"""
|
||||
try:
|
||||
if config is None:
|
||||
@@ -245,17 +253,27 @@ class SharedArgs:
|
||||
SharedArgs._cached_available_stores = []
|
||||
return
|
||||
|
||||
# Initialize registry once to filter disabled stores
|
||||
from Store.registry import Store as StoreRegistry
|
||||
|
||||
# Lightweight pass: return configured names without instantiating backends
|
||||
try:
|
||||
registry = StoreRegistry(config=config, suppress_debug=True)
|
||||
available = registry.list_backends()
|
||||
SharedArgs._cached_available_stores = available or []
|
||||
except Exception:
|
||||
# If registry creation fails, fallback to configured names
|
||||
from Store.registry import list_configured_backend_names
|
||||
SharedArgs._cached_available_stores = list_configured_backend_names(config) or []
|
||||
except Exception:
|
||||
SharedArgs._cached_available_stores = []
|
||||
|
||||
# If caller explicitly requested a full scan, instantiate registry to get
|
||||
# only backends that actually initialized successfully.
|
||||
if skip_instantiation:
|
||||
return
|
||||
|
||||
try:
|
||||
from Store.registry import Store as StoreRegistry
|
||||
registry = StoreRegistry(config=config, suppress_debug=True)
|
||||
available = registry.list_backends()
|
||||
if available:
|
||||
SharedArgs._cached_available_stores = available
|
||||
except Exception:
|
||||
# Keep the lightweight list if full initialization fails
|
||||
pass
|
||||
except Exception:
|
||||
SharedArgs._cached_available_stores = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user