Django Q: повторная регистрация и повторное выполнение асинхронной задачи после завершения
Я работаю над небольшим личным проектом Django, который в настоящее время тестируется на Heroku, и столкнулся с проблемой с Django Q (планировщик асинхронных задач, а не библиотека Q, связанная с базами данных) и Redis (в настоящее время использую Heroku Redis).
Фон
Задача, которую я пытался решить с помощью Django Q, заключалась в разгрузке длительного процесса (в данном случае серии ГИС-запросов, которые в конечном итоге сохраняются в базе данных). Я использовал сигнал post_save для запуска этого события следующим образом:
- Save "ScreeningA" model (basic site info)
- Trigger post_save signal to run "screen_by_x" function
- Within the signal function, run the "async_screening" Django Q task (in an attempt to prevent blocking the User while this runs)
- 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: Это мой первый вопрос, поэтому, пожалуйста, дайте мне знать, если я пропустил какую-либо важную информацию