fix(assets): fail safe to 503 when DB unavailable; keep --enable-assets as no-op

Address automated review feedback on the always-on assets change:
- setup_database(): on DB init failure or missing dependencies, call
  disable_assets_routes() + asset_seeder.disable() so /api/assets/* returns a
  clean 503 instead of 500s against an uninitialized DB (restores the fail-safe
  the removed else-branch used to provide).
- feature_flags: derive the advertised 'assets' capability from live backend
  availability instead of hardcoding True, so clients degrade gracefully.
- cli_args: re-add --enable-assets as a hidden deprecated no-op so existing
  launchers still passing the flag don't abort argparse.
- routes: add assets_enabled() accessor for the feature-flag derivation.
This commit is contained in:
Matt Miller 2026-06-30 15:25:26 -07:00
parent 5bcb2b085c
commit b369532116
4 changed files with 33 additions and 1 deletions

View File

@ -102,6 +102,15 @@ def disable_assets_routes() -> None:
_ASSETS_ENABLED = False
def assets_enabled() -> bool:
"""Return whether the asset routes are currently serving requests.
Reflects live backend availability: False once disable_assets_routes() has
been called (e.g. after a database init failure or missing dependencies).
"""
return _ASSETS_ENABLED
def _build_error_response(
status: int, code: str, message: str, details: dict | None = None
) -> web.Response:

View File

@ -239,6 +239,9 @@ database_default_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "user", "comfyui.db")
)
parser.add_argument("--database-url", type=str, default=f"sqlite:///{database_default_path}", help="Specify the database URL, e.g. for an in-memory database you can use 'sqlite:///:memory:'.")
# Deprecated no-op: the asset system is now always enabled. Kept (hidden) so that
# existing launchers/containers still passing --enable-assets don't fail argparse.
parser.add_argument("--enable-assets", action="store_true", help=argparse.SUPPRESS)
parser.add_argument("--enable-asset-hashing", action="store_true", help="Compute blake3 content hashes when scanning assets. Hashing enables future asset-portability features (deduplication, cross-machine model resolution) but adds startup cost and per-output cost on large models directories. Off by default; enable to opt in.")
parser.add_argument("--feature-flag", type=str, action='append', default=[], metavar="KEY[=VALUE]", help="Set a server feature flag. Use KEY=VALUE to set an explicit value, or bare KEY to set it to true. Can be specified multiple times. Boolean values (true/false) and numbers are auto-converted. Examples: --feature-flag show_signin_button=true or --feature-flag show_signin_button")
parser.add_argument("--list-feature-flags", action="store_true", help="Print the registry of known CLI-settable feature flags as JSON and exit.")

View File

@ -162,4 +162,13 @@ def get_server_features() -> dict[str, Any]:
Returns:
Dictionary of server feature flags
"""
return SERVER_FEATURE_FLAGS.copy()
features = SERVER_FEATURE_FLAGS.copy()
# Advertise the assets capability based on live backend availability rather
# than a static default, so clients degrade gracefully when the database
# failed to initialize or its dependencies are missing.
try:
from app.assets.api.routes import assets_enabled
features["assets"] = assets_enabled()
except Exception:
features["assets"] = False
return features

11
main.py
View File

@ -20,6 +20,7 @@ from app.logger import setup_logger
setup_logger(log_level=args.verbose, use_stdout=args.log_stdout)
from app.assets.seeder import asset_seeder
from app.assets.api.routes import disable_assets_routes
from app.assets.services import register_output_files
import itertools
import utils.extra_config
@ -459,6 +460,12 @@ def setup_database():
init_db()
if asset_seeder.start(roots=("models", "input", "output"), prune_first=True, compute_hashes=args.enable_asset_hashing):
logging.info("Background asset scan initiated for models, input, output")
else:
# Optional DB dependencies are missing, so init_db() is skipped and the
# asset backend has no database. Disable assets so /api/assets/* returns
# a clean 503 instead of 500s against an uninitialized DB.
disable_assets_routes()
asset_seeder.disable()
except Exception as e:
if "database is locked" in str(e):
logging.error(
@ -467,6 +474,10 @@ def setup_database():
" --database-url sqlite:///path/to/another.db"
)
sys.exit(1)
# The database is unusable. Fail safe by disabling assets so endpoints
# return 503 (service unavailable) rather than 500s on every request.
disable_assets_routes()
asset_seeder.disable()
logging.error(f"Failed to initialize database. Please ensure you have installed the latest requirements. If the error persists, please report this as in future the database will be required: {e}")