Django Q: повторная регистрация и повторное выполнение асинхронной задачи после завершения

Я работаю над небольшим личным проектом Django, который в настоящее время тестируется на Heroku, и столкнулся с проблемой с Django Q (планировщик асинхронных задач, а не библиотека Q, связанная с базами данных) и Redis (в настоящее время использую Heroku Redis).

Фон

Задача, которую я пытался решить с помощью Django Q, заключалась в разгрузке длительного процесса (в данном случае серии ГИС-запросов, которые в конечном итоге сохраняются в базе данных). Я использовал сигнал post_save для запуска этого события следующим образом:

  1. Save "ScreeningA" model (basic site info)
  2. Trigger post_save signal to run "screen_by_x" function
  3. Within the signal function, run the "async_screening" Django Q task (in an attempt to prevent blocking the User while this runs)
  4. When async task is complete, save "ScreeningB" model (more complex site screening info)

Все работает правильно, и обе модели сохраняются в базе данных. Однако после завершения этого процесса задача, похоже, повторно ставится в очередь и выполняет ту же задачу бесконечно. Я пробовал регулировать параметры Q_CLUSTER различными способами (из документации и других вопросов на stackoverflow), и та же проблема продолжает возникать.

Код

Procfile

web: gunicorn projectname.wsgi
worker: python manage.py qcluster

settings.py

Q_CLUSTER = {
    'name': 'projectname',
    'label': 'Django Q',
    'workers': 8,
    'timeout': 120,    
    'retry': 240,
    'redis': config('REDIS_URL')
}

models.py

import uuid
from django.contrib.gis.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.db import transaction
from django_q.tasks import async_task


# Screening A model
class ScreeningA(models.Model):
    id = models.UUIDField(primary_key = True, default = uuid.uuid4, editable = False)
    date_created = models.DateTimeField(auto_now_add = True)
    date_updated = models.DateTimeField(auto_now = True)
    created_by = models.ForeignKey(User, on_delete = models.CASCADE)
    name = models.CharField(max_length = 255)
    geom_point = models.PointField(blank=True, null=True)
    complete = models.BooleanField(default=False)

    # Additional model fields
    # excluded for simplicity

    # Define save method
    def save(self, *args, **kwargs):
        pnt_wkt = self.geom_point

        # Basic geospatial queries and model logic (i.e., self.item)
        # excluded for simplicity

        super(ScreeningA, self).save(*args, **kwargs)

    # Define string representation
    def __str__(self):
        return self.name


# Screening B model
class ScreeningB(models.Model):
    id = models.UUIDField(primary_key = True, default = uuid.uuid4, editable = False)
    date_created = models.DateTimeField(auto_now_add = True)
    date_updated = models.DateTimeField(auto_now = True)
    site = models.ForeignKey(ScreeningA, on_delete = models.CASCADE)

    # Additional model fields
    # excluded for simplicity


# Define Screen by X Signal
def screen_by_x(sender, instance, **kwargs):
    current_site = instance.id

    transaction.on_commit(lambda: async_task('screening.services.async_screening', current_site)


# Connect Signals
post_save.connect(screen_by_x, sender = ScreeningA)

services.py (расположение асинхронных задач Django Q)

# Define async_screening Function
def async_screening(current_site):
    from .models import ScreeningA, ScreeningB

    site = ScreeningA.objects.get(id=current_site)
    pnt_wkt = site.geom_point

    obj, created = ScreeningB.objects.update_or_create(
        site = ScreeningA.objects.get(id=current_site),
        defaults={

            # More complex geospatial queries and model logic
            # excluded for simplicity

        }
    )

    site.complete = True
    site.save(update_fields=["complete"]) 

    return 'Complete'

Заранее благодарю вас за любое понимание или поддержку, которую вы можете оказать.

PS: Это мой первый вопрос, поэтому, пожалуйста, дайте мне знать, если я пропустил какую-либо важную информацию

Вернуться на верх