mirror of
https://github.com/rommapp/romm.git
synced 2026-10-12 02:21:58 +00:00
refactor(sync): make SSH sync handler lazy-initialized
The module-level SSHSyncHandler() singleton ran filesystem side effects
(mkdir on SYNC_SSH_KEYS_PATH) at import time, which meant even default
installs with push-pull sync disabled would touch /romm/sync — and the
previous tolerate-and-warn fallback could leave users wondering why
sync silently does nothing.
Replace the eager singleton with a functools.cache'd factory. The
handler is now constructed on first use, so:
- Default-install users (ENABLE_SYNC_PUSH_PULL=false, no manual sync
triggered) never touch /romm/sync.
- Users opting in get a clear, actionable RuntimeError pointing at
the unwritable path and the env var to override, at the call site
rather than buried in a startup stack trace.
Also document in env.template that enabling either sync mode requires
a writable volume at $ROMM_BASE_PATH/sync.
This commit is contained in:
@@ -11,6 +11,7 @@ device's sync_config.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import hashlib
|
||||
import os
|
||||
import tempfile
|
||||
@@ -51,12 +52,12 @@ class SSHSyncHandler:
|
||||
self.keys_path = Path(SYNC_SSH_KEYS_PATH)
|
||||
try:
|
||||
self.keys_path.mkdir(parents=True, exist_ok=True)
|
||||
except OSError:
|
||||
log.warning(
|
||||
f"Could not create or access {self.keys_path}; "
|
||||
"push-pull sync will be unavailable until the directory is writable "
|
||||
"or keys are mounted at this path."
|
||||
)
|
||||
except OSError as e:
|
||||
raise RuntimeError(
|
||||
f"SSH keys directory {self.keys_path} is not writable ({e}). "
|
||||
"Mount a writable volume at this path, or set SYNC_SSH_KEYS_PATH "
|
||||
"to a writable location, to use push-pull sync."
|
||||
) from e
|
||||
|
||||
def _resolve_key_path(self, device_id: str, sync_config: dict) -> str | None:
|
||||
"""Resolve the SSH key path for a device.
|
||||
@@ -231,4 +232,12 @@ class SSHSyncHandler:
|
||||
log.info(f"Deleted remote file: {remote_path}")
|
||||
|
||||
|
||||
ssh_sync_handler = SSHSyncHandler()
|
||||
@functools.cache
|
||||
def get_ssh_sync_handler() -> SSHSyncHandler:
|
||||
"""Lazily instantiate the SSH sync handler on first use.
|
||||
|
||||
Deferred so that startup doesn't fail when push-pull sync is unconfigured
|
||||
or the keys directory is not writable. The handler raises a clear error
|
||||
at call time if the directory cannot be created.
|
||||
"""
|
||||
return SSHSyncHandler()
|
||||
|
||||
@@ -21,7 +21,7 @@ from handler.database import (
|
||||
)
|
||||
from handler.filesystem import fs_asset_handler
|
||||
from handler.sync.comparison import compare_save_state
|
||||
from handler.sync.ssh_handler import ssh_sync_handler
|
||||
from handler.sync.ssh_handler import get_ssh_sync_handler
|
||||
from logger.formatter import highlight as hl
|
||||
from logger.logger import log
|
||||
from models.device import Device, SyncMode
|
||||
@@ -65,6 +65,7 @@ async def run_push_pull_sync(
|
||||
|
||||
async def _sync_device(device: Device, session_id: int | None = None) -> dict:
|
||||
"""Perform push-pull sync for a single device."""
|
||||
ssh_sync_handler = get_ssh_sync_handler()
|
||||
sync_config = device.sync_config or {}
|
||||
if not sync_config.get("ssh_host"):
|
||||
log.warning(f"Push-pull device {device.id} has no ssh_host configured")
|
||||
@@ -227,6 +228,7 @@ async def _process_remote_save(
|
||||
remote_save,
|
||||
) -> str:
|
||||
"""Process a single remote save file. Returns action taken."""
|
||||
ssh_sync_handler = get_ssh_sync_handler()
|
||||
# Look up platform
|
||||
platform = db_platform_handler.get_platform_by_fs_slug(remote_save.platform_slug)
|
||||
if not platform:
|
||||
@@ -340,6 +342,7 @@ async def _push_missing_saves(
|
||||
save_directories: list[dict],
|
||||
) -> int:
|
||||
"""Push server saves that are missing from the device."""
|
||||
ssh_sync_handler = get_ssh_sync_handler()
|
||||
pushed = 0
|
||||
|
||||
# Build set of remote filenames per platform
|
||||
|
||||
+2
-1
@@ -87,7 +87,8 @@ SCHEDULED_CONVERT_IMAGES_TO_WEBP_CRON=0 4 * * * # Cron expression for scheduled
|
||||
ENABLE_SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC=false # Enable scheduled RetroAchievements progress sync
|
||||
SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC_CRON=0 4 * * * # Cron expression for scheduled RetroAchievements sync
|
||||
|
||||
# Sync
|
||||
# Sync — both modes use $ROMM_BASE_PATH/sync by default. Mount a writable
|
||||
# volume at that path when enabling either feature.
|
||||
ENABLE_SYNC_FOLDER_WATCHER=false # Watch the sync folder and trigger scans on change
|
||||
SYNC_FOLDER_SCAN_DELAY=2 # Delay in minutes before scanning after a sync folder change
|
||||
ENABLE_SYNC_PUSH_PULL=false # Enable scheduled sync push/pull
|
||||
|
||||
Reference in New Issue
Block a user