Delete celery tasks properly during m3u account deletion.

This commit is contained in:
SergeantPanda 2025-05-09 12:00:57 -05:00
parent 8779e6a8cf
commit 6afccadf74
2 changed files with 83 additions and 5 deletions

View file

@ -2,9 +2,12 @@
from django.db.models.signals import post_save, post_delete, pre_save
from django.dispatch import receiver
from .models import M3UAccount
from .tasks import refresh_single_m3u_account, refresh_m3u_groups
from .tasks import refresh_single_m3u_account, refresh_m3u_groups, delete_m3u_refresh_task_by_id
from django_celery_beat.models import PeriodicTask, IntervalSchedule
import json
import logging
logger = logging.getLogger(__name__)
@receiver(post_save, sender=M3UAccount)
def refresh_account_on_save(sender, instance, created, **kwargs):
@ -65,9 +68,21 @@ def delete_refresh_task(sender, instance, **kwargs):
"""
Delete the associated Celery Beat periodic task when a Channel is deleted.
"""
if instance.refresh_task:
instance.refresh_task.interval.delete()
instance.refresh_task.delete()
try:
# First try the foreign key relationship to find the task ID
task = None
if instance.refresh_task:
logger.info(f"Found task via foreign key: {instance.refresh_task.id} for M3UAccount {instance.id}")
task = instance.refresh_task
# Use the helper function to delete the task
if task:
delete_m3u_refresh_task_by_id(instance.id)
else:
# Otherwise use the helper function
delete_m3u_refresh_task_by_id(instance.id)
except Exception as e:
logger.error(f"Error in delete_refresh_task signal handler: {str(e)}", exc_info=True)
@receiver(pre_save, sender=M3UAccount)
def update_status_on_active_change(sender, instance, **kwargs):

View file

@ -733,6 +733,60 @@ def refresh_m3u_groups(account_id, use_cache=False, full_refresh=False):
return extinf_data, groups
def delete_m3u_refresh_task_by_id(account_id):
"""
Delete the periodic task associated with an M3U account ID.
Can be called directly or from the post_delete signal.
Returns True if a task was found and deleted, False otherwise.
"""
try:
task = None
task_name = f"m3u_account-refresh-{account_id}"
# Look for task by name
try:
from django_celery_beat.models import PeriodicTask, IntervalSchedule
task = PeriodicTask.objects.get(name=task_name)
logger.info(f"Found task by name: {task.id} for M3UAccount {account_id}")
except PeriodicTask.DoesNotExist:
logger.warning(f"No PeriodicTask found with name {task_name}")
return False
# Now delete the task and its interval
if task:
# Store interval info before deleting the task
interval_id = None
if hasattr(task, 'interval') and task.interval:
interval_id = task.interval.id
# Count how many TOTAL tasks use this interval (including this one)
tasks_with_same_interval = PeriodicTask.objects.filter(interval_id=interval_id).count()
logger.info(f"Interval {interval_id} is used by {tasks_with_same_interval} tasks total")
# Delete the task first
task_id = task.id
task.delete()
logger.info(f"Successfully deleted periodic task {task_id}")
# Now check if we should delete the interval
# We only delete if it was the ONLY task using this interval
if interval_id and tasks_with_same_interval == 1:
try:
interval = IntervalSchedule.objects.get(id=interval_id)
logger.info(f"Deleting interval schedule {interval_id} (not shared with other tasks)")
interval.delete()
logger.info(f"Successfully deleted interval {interval_id}")
except IntervalSchedule.DoesNotExist:
logger.warning(f"Interval {interval_id} no longer exists")
elif interval_id:
logger.info(f"Not deleting interval {interval_id} as it's shared with {tasks_with_same_interval-1} other tasks")
return True
return False
except Exception as e:
logger.error(f"Error deleting periodic task for M3UAccount {account_id}: {str(e)}", exc_info=True)
return False
@shared_task
def refresh_single_m3u_account(account_id):
"""Splits M3U processing into chunks and dispatches them as parallel tasks."""
@ -758,8 +812,17 @@ def refresh_single_m3u_account(account_id):
filters = list(account.filters.all())
except M3UAccount.DoesNotExist:
# The M3U account doesn't exist, so delete the periodic task if it exists
logger.warning(f"M3U account with ID {account_id} not found, but task was triggered. Cleaning up orphaned task.")
# Call the helper function to delete the task
if delete_m3u_refresh_task_by_id(account_id):
logger.info(f"Successfully cleaned up orphaned task for M3U account {account_id}")
else:
logger.info(f"No orphaned task found for M3U account {account_id}")
release_task_lock('refresh_single_m3u_account', account_id)
return f"M3UAccount with ID={account_id} not found or inactive."
return f"M3UAccount with ID={account_id} not found or inactive, task cleaned up"
# Fetch M3U lines and handle potential issues
extinf_data = []