diff --git a/apps/epg/tasks.py b/apps/epg/tasks.py index 17b9faf8..d808a4c6 100644 --- a/apps/epg/tasks.py +++ b/apps/epg/tasks.py @@ -23,7 +23,7 @@ from asgiref.sync import async_to_sync from channels.layers import get_channel_layer from .models import EPGSource, EPGData, ProgramData -from core.utils import acquire_task_lock, release_task_lock, send_websocket_update +from core.utils import acquire_task_lock, release_task_lock, send_websocket_update, cleanup_memory logger = logging.getLogger(__name__) @@ -826,8 +826,8 @@ def parse_channels_only(source): # Check final memory usage after clearing process gc.collect() - - + # Add comprehensive cleanup at end of channel parsing + cleanup_memory(log_usage=True, force_collection=True) @shared_task @@ -1133,6 +1133,8 @@ def parse_programs_for_tvg_id(epg_id): # Force garbage collection before releasing lock gc.collect() + # Add comprehensive cleanup before releasing lock + cleanup_memory(log_usage=True, force_collection=True) release_task_lock('parse_epg_programs', epg_id) @@ -1281,6 +1283,9 @@ def parse_programs_for_source(epg_source, tvg_id=None): if 'process' in locals() and process is not None: process = None + # Add comprehensive memory cleanup at the end + cleanup_memory(log_usage=True, force_collection=True) + def fetch_schedules_direct(source): logger.info(f"Fetching Schedules Direct data from source: {source.name}") diff --git a/core/utils.py b/core/utils.py index abe1c1f2..7143a349 100644 --- a/core/utils.py +++ b/core/utils.py @@ -245,3 +245,40 @@ def monitor_memory_usage(func): return result return wrapper + +def cleanup_memory(log_usage=True, force_collection=True): + """ + Comprehensive memory cleanup function to reduce memory footprint + + Args: + log_usage: Whether to log memory usage before and after cleanup + force_collection: Whether to force garbage collection + """ + if log_usage: + try: + import psutil + process = psutil.Process() + before_mem = process.memory_info().rss / (1024 * 1024) + logger.debug(f"Memory before cleanup: {before_mem:.2f} MB") + except (ImportError, Exception) as e: + logger.debug(f"Error getting memory usage: {e}") + + # Clear any object caches from Django ORM + from django.db import connection, reset_queries + reset_queries() + + # Force garbage collection + if force_collection: + # Run full collection + gc.collect(generation=2) + # Clear cyclic references + gc.collect(generation=0) + + if log_usage: + try: + import psutil + process = psutil.Process() + after_mem = process.memory_info().rss / (1024 * 1024) + logger.debug(f"Memory after cleanup: {after_mem:.2f} MB (change: {after_mem-before_mem:.2f} MB)") + except (ImportError, Exception): + pass