From 8344cf2c7a9fd713824cf1191669d7271c956bf5 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:25:44 -0700 Subject: [PATCH] =?UTF-8?q?Decouple=20wishlist=20processing=20and=20watchl?= =?UTF-8?q?ist=20scanning=20=E2=80=94=20allow=20concurrent=20execution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed cross-guards that blocked wishlist downloads while watchlist scans ran (and vice versa). Downloads use bandwidth, scans use API calls — different resources. The per-call rate limiter handles any API contention. - Automation engine: each handler now has self-only guard (no cross-block) - _process_wishlist_automatically: removed watchlist scanning check - Pipeline Phase 4: removed watchlist scanning check - Manual watchlist scan endpoint: removed wishlist processing check Users with large watchlists (6+ hour scans) will now see downloads starting immediately instead of waiting for the scan to finish. --- web_server.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/web_server.py b/web_server.py index 8c6884c7..40464f14 100644 --- a/web_server.py +++ b/web_server.py @@ -530,9 +530,14 @@ def _register_automation_handlers(): finally: _scan_library_automation_id = None - cross_guard = lambda: is_wishlist_actually_processing() or is_watchlist_actually_scanning() - automation_engine.register_action_handler('process_wishlist', _auto_process_wishlist, cross_guard) - automation_engine.register_action_handler('scan_watchlist', _auto_scan_watchlist, cross_guard) + # Self-guards only — prevent duplicate runs of the same operation, + # but allow wishlist processing and watchlist scanning to run concurrently. + # Downloads use bandwidth (Soulseek/Tidal/etc), scans use API calls — different resources. + # The per-call rate limiter handles any API contention during post-processing. + automation_engine.register_action_handler('process_wishlist', _auto_process_wishlist, + guard_fn=lambda: is_wishlist_actually_processing()) + automation_engine.register_action_handler('scan_watchlist', _auto_scan_watchlist, + guard_fn=lambda: is_watchlist_actually_scanning()) automation_engine.register_action_handler('scan_library', _auto_scan_library, lambda: _scan_library_automation_id is not None) @@ -1156,14 +1161,14 @@ def _register_automation_handlers(): log_line='Phase 4: Wishlist', log_type='info') try: - if not is_wishlist_actually_processing() and not is_watchlist_actually_scanning(): + if not is_wishlist_actually_processing(): _process_wishlist_automatically(automation_id=None) _update_automation_progress(automation_id, log_line='Wishlist processing triggered', log_type='success') wishlist_queued = 1 else: _update_automation_progress(automation_id, - log_line='Wishlist/watchlist already running — skipped', log_type='skip') + log_line='Wishlist already running — skipped', log_type='skip') except Exception as e: _update_automation_progress(automation_id, log_line=f'Wishlist error: {e}', log_type='warning') @@ -22279,7 +22284,6 @@ def _process_wishlist_automatically(automation_id=None): # Check conditions and set flag should_skip_already_running = False - should_skip_watchlist_conflict = False with wishlist_timer_lock: # Re-check inside lock to handle race conditions @@ -22287,11 +22291,6 @@ def _process_wishlist_automatically(automation_id=None): print("⚠️ [Auto-Wishlist] Already processing (race condition check), skipping.") should_skip_already_running = True - # Check if watchlist scan is currently running (using smart detection) - elif is_watchlist_actually_scanning(): - print("👁️ Watchlist scan in progress, skipping automatic wishlist processing to avoid conflicts.") - should_skip_watchlist_conflict = True - else: # Set flag and timestamp import time @@ -22299,7 +22298,7 @@ def _process_wishlist_automatically(automation_id=None): wishlist_auto_processing_timestamp = time.time() print(f"🔒 [Auto-Wishlist] Flag set at timestamp {wishlist_auto_processing_timestamp}") - if should_skip_already_running or should_skip_watchlist_conflict: + if should_skip_already_running: return # Use app context for database operations @@ -37778,10 +37777,6 @@ def start_watchlist_scan(): logger.info(f"Starting watchlist scan with {active_provider} provider") - # Check if wishlist auto-processing is currently running (using smart detection) - if is_wishlist_actually_processing(): - return jsonify({"success": False, "error": "Wishlist auto-processing is currently running. Please wait for it to complete before starting a watchlist scan."}), 409 - # Check if watchlist is already scanning if is_watchlist_actually_scanning(): return jsonify({"success": False, "error": "Watchlist scan is already in progress."}), 409