Update web_server.py

This commit is contained in:
Broque Thomas 2025-09-04 15:03:17 -07:00
parent f1bc9c6f24
commit 58af02a954

View file

@ -209,8 +209,6 @@ class WebUIDownloadMonitor:
def _monitor_loop(self): def _monitor_loop(self):
"""Main monitoring loop - checks downloads every 1 second for responsive web UX""" """Main monitoring loop - checks downloads every 1 second for responsive web UX"""
import time
while self.monitoring and self.monitored_batches: while self.monitoring and self.monitored_batches:
try: try:
self._check_all_downloads() self._check_all_downloads()
@ -314,7 +312,7 @@ class WebUIDownloadMonitor:
return False return False
else: else:
queue_time = current_time - task['queued_start_time'] queue_time = current_time - task['queued_start_time']
if queue_time > 90: if queue_time > 120: # Increased timeout to reduce retry spam
# Track retry attempts to prevent rapid loops # Track retry attempts to prevent rapid loops
retry_count = task.get('stuck_retry_count', 0) retry_count = task.get('stuck_retry_count', 0)
last_retry = task.get('last_retry_time', 0) last_retry = task.get('last_retry_time', 0)
@ -333,6 +331,9 @@ class WebUIDownloadMonitor:
print(f"❌ Task failed after 3 retry attempts (queue timeout)") print(f"❌ Task failed after 3 retry attempts (queue timeout)")
task['status'] = 'failed' task['status'] = 'failed'
task['error_message'] = 'Failed after multiple queue timeout retries' task['error_message'] = 'Failed after multiple queue timeout retries'
# Clear timers to prevent further retry loops
task.pop('queued_start_time', None)
task.pop('downloading_start_time', None)
return False return False
# Check for downloading at 0% timeout (90 seconds like GUI) # Check for downloading at 0% timeout (90 seconds like GUI)
@ -342,7 +343,7 @@ class WebUIDownloadMonitor:
return False return False
else: else:
download_time = current_time - task['downloading_start_time'] download_time = current_time - task['downloading_start_time']
if download_time > 90: if download_time > 120: # Increased timeout to reduce retry spam
retry_count = task.get('stuck_retry_count', 0) retry_count = task.get('stuck_retry_count', 0)
last_retry = task.get('last_retry_time', 0) last_retry = task.get('last_retry_time', 0)
@ -359,6 +360,9 @@ class WebUIDownloadMonitor:
print(f"❌ Task failed after 3 retry attempts (0% progress timeout)") print(f"❌ Task failed after 3 retry attempts (0% progress timeout)")
task['status'] = 'failed' task['status'] = 'failed'
task['error_message'] = 'Failed after multiple 0% progress retries' task['error_message'] = 'Failed after multiple 0% progress retries'
# Clear timers to prevent further retry loops
task.pop('queued_start_time', None)
task.pop('downloading_start_time', None)
return False return False
else: else:
# Progress being made, reset timers and retry counts # Progress being made, reset timers and retry counts
@ -404,21 +408,21 @@ class WebUIDownloadMonitor:
# Only attempt cancellation if we have what looks like a proper download ID # Only attempt cancellation if we have what looks like a proper download ID
# (not a filename fallback which would be much longer) # (not a filename fallback which would be much longer)
if download_id and username and len(download_id) < 100: if download_id and username and isinstance(download_id, str) and len(download_id) < 100:
print(f"🚫 Attempting to cancel stuck download: {os.path.basename(download_id)} from {username} (task: {task_id[:8]}...)") print(f"🚫 Attempting to cancel stuck download: {os.path.basename(str(download_id))} from {username} (task: {task_id[:8]}...)")
try: try:
success = asyncio.run(soulseek_client.cancel_download(download_id, username, remove=False)) success = asyncio.run(soulseek_client.cancel_download(download_id, username, remove=False))
if success: if success:
print(f"✅ Successfully cancelled download {download_id[:8]}... from {username}") print(f"✅ Successfully cancelled download {str(download_id)[:8]}... from {username}")
# Clear any stored download info to prevent status conflicts # Clear any stored download info to prevent status conflicts
task.pop('soulseek_download_id', None) task.pop('soulseek_download_id', None)
task.pop('soulseek_username', None) task.pop('soulseek_username', None)
else: else:
print(f"⚠️ Cancel request failed for {download_id[:8]}... - all API endpoints returned errors, proceeding with retry anyway") print(f"⚠️ Cancel request failed for {str(download_id)[:8]}... - all API endpoints returned errors, proceeding with retry anyway")
except Exception as e: except Exception as e:
print(f"⚠️ Cancel exception for {download_id[:8]}...: {str(e)[:150]}, proceeding with retry anyway") print(f"⚠️ Cancel exception for {str(download_id)[:8]}...: {str(e)[:150]}, proceeding with retry anyway")
else: else:
print(f"⚠️ Invalid download ID for cancellation (len={len(download_id) if download_id else 0}, username={bool(username)}), proceeding with retry") print(f"⚠️ Skipping cancellation - invalid data (ID len={len(str(download_id)) if download_id else 0}, username='{username}'), proceeding with retry")
except Exception as e: except Exception as e:
print(f"⚠️ Error in cancellation logic, proceeding with retry: {e}") print(f"⚠️ Error in cancellation logic, proceeding with retry: {e}")
@ -469,7 +473,6 @@ def cleanup_monitor():
download_monitor.monitoring = False download_monitor.monitoring = False
download_monitor.monitored_batches.clear() download_monitor.monitored_batches.clear()
# Give the thread a moment to exit cleanly # Give the thread a moment to exit cleanly
import time
time.sleep(0.5) time.sleep(0.5)
def signal_handler(signum, frame): def signal_handler(signum, frame):
@ -2054,7 +2057,6 @@ def check_artist_discography_completion_stream(artist_id):
yield f"data: {json.dumps(completion_data)}\n\n" yield f"data: {json.dumps(completion_data)}\n\n"
# Small delay to make the streaming effect visible # Small delay to make the streaming effect visible
import time
time.sleep(0.1) # 100ms delay between items time.sleep(0.1) # 100ms delay between items
except Exception as e: except Exception as e:
@ -7321,7 +7323,6 @@ def _run_sync_task(playlist_id, playlist_name, tracks_json):
"""The actual sync function that runs in the background thread.""" """The actual sync function that runs in the background thread."""
global sync_states, sync_service global sync_states, sync_service
import time
task_start_time = time.time() task_start_time = time.time()
print(f"🚀 [TIMING] _run_sync_task STARTED for playlist '{playlist_name}' at {time.strftime('%H:%M:%S')}") print(f"🚀 [TIMING] _run_sync_task STARTED for playlist '{playlist_name}' at {time.strftime('%H:%M:%S')}")
print(f"📊 Received {len(tracks_json)} tracks from frontend") print(f"📊 Received {len(tracks_json)} tracks from frontend")
@ -7528,7 +7529,6 @@ def _run_sync_task(playlist_id, playlist_name, tracks_json):
@app.route('/api/sync/start', methods=['POST']) @app.route('/api/sync/start', methods=['POST'])
def start_playlist_sync(): def start_playlist_sync():
"""Starts a new sync process for a given playlist.""" """Starts a new sync process for a given playlist."""
import time
request_start_time = time.time() request_start_time = time.time()
print(f"⏱️ [TIMING] Sync request received at {time.strftime('%H:%M:%S')}") print(f"⏱️ [TIMING] Sync request received at {time.strftime('%H:%M:%S')}")