Django 2.0中如何监控Task模型的deadline并触发通知等操作?
Absolutely, Celery is perfectly suited for this scenario! Handling time-based notifications like deadline reminders is one of the core use cases for Celery in Django projects. Let me walk you through how to implement this effectively with Django 2.0:
一、基础前提
First, make sure you've got Celery set up in your Django project with a broker (Redis or RabbitMQ work great) and result backend configured. Also, confirm your Task model's deadline field is a timezone-aware DateTimeField (enable USE_TZ = True in your Django settings to avoid timezone headaches).
二、两种推荐实现方式
1. 延迟任务(首选方案)
When a Task is created or updated, calculate the exact time you need to send the notification, then schedule a delayed Celery task to run at that moment. This is more efficient than periodic scans because it only runs when needed.
First, define your notification task in tasks.py:
from celery import shared_task from django.utils import timezone from .models import Task from django.core.mail import send_mail @shared_task def send_deadline_alert(task_id): try: task = Task.objects.get(id=task_id) user = task.user # Assuming your Task model has a user foreign key # Replace this with your actual notification logic (email, in-app message, push, etc.) send_mail( subject=f"Task Deadline Alert: {task.title}", message=f"Hi {user.username}, your task '{task.title}' is either due in 1 hour or has already expired. Please take action!", from_email="notifications@yourdomain.com", recipient_list=[user.email], fail_silently=False, ) except Task.DoesNotExist: # Task might have been deleted before the alert runs—safe to ignore pass
Then, use a Django signal to schedule the task whenever a Task is saved:
# In signals.py or your views file from django.db.models.signals import post_save from django.dispatch import receiver from .models import Task from .tasks import send_deadline_alert from django.utils import timezone @receiver(post_save, sender=Task) def schedule_deadline_alert(sender, instance, created, **kwargs): now = timezone.now() reminder_time = instance.deadline - timezone.timedelta(hours=1) if reminder_time > now: # Calculate delay in seconds until the reminder needs to run delay_seconds = (reminder_time - now).total_seconds() send_deadline_alert.apply_async(args=[instance.id], countdown=delay_seconds) elif instance.deadline <= now: # Deadline is already past—send alert immediately send_deadline_alert.delay(instance.id)
2. 周期性扫描任务(备选方案)
If you're worried about delayed tasks getting lost during server restarts (though Redis/RabbitMQ can persist tasks), you can use Celery Beat to run a periodic scan for tasks approaching their deadlines.
First, configure Celery Beat in your celery.py:
from celery import Celery from celery.schedules import crontab app = Celery('your_project_name') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() # Schedule a scan every minute app.conf.beat_schedule = { 'check-upcoming-deadlines': { 'task': 'your_app.tasks.check_deadline_tasks', 'schedule': crontab(minute='*/1'), }, }
Then write the scanning task:
# tasks.py @shared_task def check_deadline_tasks(): now = timezone.now() # Find tasks that are within 1 hour of deadline, or past it, and haven't been notified yet tasks_to_alert = Task.objects.filter( deadline__range=[now - timezone.timedelta(minutes=1), now + timezone.timedelta(hours=1)], notification_sent=False # Add a BooleanField to Task to track if alert was sent ) for task in tasks_to_alert: # Send your notification here send_mail(...) # Mark as notified to avoid duplicates task.notification_sent = True task.save()
三、关键注意事项
- Timezone Consistency: Ensure Django and Celery use the same timezone (set
CELERY_TIMEZONEin your settings to matchTIME_ZONE). - Task Persistence: Use a persistent broker like Redis or RabbitMQ to prevent delayed tasks from being lost on server restart.
- Avoid Duplicate Alerts: Add a
notification_sentBooleanField to yourTaskmodel to track if the alert has already been sent. - Error Handling: Always include try/except blocks in your Celery tasks to handle edge cases like deleted tasks.
内容的提问来源于stack exchange,提问作者bohdan.k

