Celery定时任务组件之Django+Celery项目实战教程

Written by

in

文章目录
  • task_manager/ ├── task_manager/ │ ├── __init__.py │ ├── celery.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── tasks/ │ ├── migrations/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── tasks.py │ ├── urls.py │ └── views.py ├── manage.py └── db.sqlite3
  • 动态任务管理:通过 API 创建 / 更新 / 删除定时任务 任务执行记录:自动记录任务执行结果和状态 失败重试机制:任务失败时自动重试(最多 3 次) 多种调度方式:支持周期性任务和一次性任务 可视化管理:通过 Django Admin 界面管理定时任务
  • 添加任务参数支持,允许在创建任务时传递参数 实现任务暂停 / 恢复功能 添加任务优先级队列配置 集成监控系统(如 Prometheus+Grafana) 实现任务执行结果的异步通知(邮件、短信等) 这个实现提供了一个完整的 Django+Celery 定时任务系统,支持动态管理和监控,可直接用于生产环境。
  • 以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。 您可能感兴趣的文章: django celery定时任务实战详解 如何使用celery进行异步处理和定时任务(django) Django中使用Celery执行定时任务问题 django中celery的定时任务使用 django-celery-beat搭建定时任务的实现 Django初步使用Celery处理耗时任务和定时任务问题
  • 目录
    • 一、项目初始化
      • 1. 创建虚拟环境并安装依赖
      • 2. 创建 Django 项目和应用
      • 3. 配置项目(task_manager/settings.py)
    • 二、Celery 集成配置
      • 1. 创建 Celery 应用(task_manager/celery.py)
      • 2. 初始化 Celery(task_manager/__init__.py)
    • 三、Model 开发
      • 创建任务模型(tasks/models.py)
      • 迁移数据库
    • 四、接口开发
      • 1. 创建序列化器(tasks/serializers.py)
      • 2. 创建视图集(tasks/views.py)
      • 3. 配置 URL(tasks/urls.py)
      • 4. 项目 URL 配置(task_manager/urls.py)
    • 五、创建示例任务
      • 定义任务函数(tasks/tasks.py)
    • 六、启动服务
      • 1. 启动 Redis
      • 2. 启动 Celery Worker
      • 3. 启动 Celery Beat
      • 4. 启动 Django 开发服务器
    • 七、API 测试
      • 1. 创建周期性任务
      • 2. 查看任务列表
      • 3. 查看执行日志
    • 项目结构
      • 关键特性说明
        • 扩展建议
          • 总结

            # 创建虚拟环境
            python3 -m venv myenv
            source myenv/bin/activate
            
            # 安装依赖
            pip install django celery redis django-celery-beat
            

            # 创建项目
            django-admin startproject task_manager
            cd task_manager
            
            # 创建应用
            python manage.py startapp tasks
            

            INSTALLED_APPS = [
                # ...
                'django_celery_beat',
                'django_celery_results',
                'tasks',
            ]
            
            # 数据库配置
            DATABASES = {
                'default': {
                    'ENGINE': 'django.db.backends.sqlite3',
                    'NAME': BASE_DIR / 'db.sqlite3',
                }
            }
            
            # Celery配置
            CELERY_BROKER_URL = 'redis://localhost:6379/0'
            CELERY_RESULT_BACKEND = 'django-db'  # 使用django-celery-results存储结果
            CELERY_ACCEPT_CONTENT = ['json']
            CELERY_TASK_SERIALIZER = 'json'
            CELERY_RESULT_SERIALIZER = 'json'
            CELERY_TIMEZONE = 'Asia/Shanghai'
            

            from __future__ import absolute_import, unicode_literals
            import os
            from celery import Celery
            
            os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'task_manager.settings')
            
            app = Celery('task_manager')
            app.config_from_object('django.conf:settings', namespace='CELERY')
            app.autodiscover_tasks()
            
            @app.task(bind=True)
            def debug_task(self):
                print(f'Request: {self.request!r}')
            

            from __future__ import absolute_import, unicode_literals
            from .celery import app as celery_app
            
            __all__ = ('celery_app',)
            

            from django.db import models
            from django.utils import timezone
            
            class ScheduledTask(models.Model):
                TASK_TYPES = (
                    ('periodic', '周期性任务'),
                    ('one_time', '一次性任务'),
                )
                
                name = models.CharField('任务名称', max_length=100)
                task_type = models.CharField('任务类型', max_length=20, choices=TASK_TYPES)
                task_function = models.CharField('任务函数', max_length=200)
                cron_expression = models.CharField('Cron表达式', max_length=100, blank=True, null=True)
                interval_seconds = models.IntegerField('间隔秒数', blank=True, null=True)
                next_run_time = models.DateTimeField('下次执行时间', blank=True, null=True)
                is_active = models.BooleanField('是否激活', default=True)
                created_at = models.DateTimeField('创建时间', auto_now_add=True)
                updated_at = models.DateTimeField('更新时间', auto_now=True)
                
                def __str__(self):
                    return self.name
                
                class Meta:
                    verbose_name = '定时任务'
                    verbose_name_plural = '定时任务列表'
            
            class TaskExecutionLog(models.Model):
                task = models.ForeignKey(ScheduledTask, on_delete=models.CASCADE, related_name='logs')
                execution_time = models.DateTimeField('执行时间', auto_now_add=True)
                status = models.CharField('执行状态', max_length=20, choices=(
                    ('success', '成功'),
                    ('failed', '失败'),
                ))
                result = models.TextField('执行结果', blank=True, null=True)
                error_message = models.TextField('错误信息', blank=True, null=True)
                
                def __str__(self):
                    return f"{self.task.name} - {self.execution_time}"
                
                class Meta:
                    verbose_name = '任务执行日志'
                    verbose_name_plural = '任务执行日志列表'
            

            python manage.py makemigrations
            python manage.py migrate
            

            from rest_framework import serializers
            from .models import ScheduledTask, TaskExecutionLog
            
            class ScheduledTaskSerializer(serializers.ModelSerializer):
                class Meta:
                    model = ScheduledTask
                    fields = '__all__'
            
            class TaskExecutionLogSerializer(serializers.ModelSerializer):
                class Meta:
                    model = TaskExecutionLog
                    fields = '__all__'
            

            from rest_framework import viewsets, status
            from rest_framework.response import Response
            from .models import ScheduledTask, TaskExecutionLog
            from .serializers import ScheduledTaskSerializer, TaskExecutionLogSerializer
            from celery import current_app
            from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule
            import json
            
            class ScheduledTaskViewSet(viewsets.ModelViewSet):
                queryset = ScheduledTask.objects.all()
                serializer_class = ScheduledTaskSerializer
                
                def create(self, request, *args, **kwargs):
                    serializer = self.get_serializer(data=request.data)
                    serializer.is_valid(raise_exception=True)
                    
                    # 创建Celery定时任务
                    task = serializer.save()
                    self._create_celery_task(task)
                    
                    headers = self.get_success_headers(serializer.data)
                    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
                
                def update(self, request, *args, **kwargs):
                    partial = kwargs.pop('partial', False)
                    instance = self.get_object()
                    serializer = self.get_serializer(instance, data=request.data, partial=partial)
                    serializer.is_valid(raise_exception=True)
                    
                    # 更新Celery定时任务
                    task = serializer.save()
                    self._update_celery_task(task)
                    
                    return Response(serializer.data)
                
                def destroy(self, request, *args, **kwargs):
                    instance = self.get_object()
                    
                    # 删除Celery定时任务
                    self._delete_celery_task(instance)
                    
                    self.perform_destroy(instance)
                    return Response(status=status.HTTP_204_NO_CONTENT)
                
                def _create_celery_task(self, task):
                    if task.task_type == 'periodic':
                        # 创建间隔调度
                        schedule, _ = IntervalSchedule.objects.get_or_create(
                            every=task.interval_seconds,
                            period=IntervalSchedule.SECONDS,
                        )
                        PeriodicTask.objects.create(
                            interval=schedule,
                            name=task.name,
                            task=task.task_function,
                            enabled=task.is_active,
                            args=json.dumps([]),
                            kwargs=json.dumps({}),
                        )
                    elif task.task_type == 'one_time':
                        # 一次性任务使用ETA
                        pass
                
                def _update_celery_task(self, task):
                    try:
                        periodic_task = PeriodicTask.objects.get(name=task.name)
                        if task.task_type == 'periodic':
                            schedule, _ = IntervalSchedule.objects.get_or_create(
                                every=task.interval_seconds,
                                period=IntervalSchedule.SECONDS,
                            )
                            periodic_task.interval = schedule
                        periodic_task.enabled = task.is_active
                        periodic_task.save()
                    except PeriodicTask.DoesNotExist:
                        self._create_celery_task(task)
                
                def _delete_celery_task(self, task):
                    try:
                        periodic_task = PeriodicTask.objects.get(name=task.name)
                        periodic_task.delete()
                    except PeriodicTask.DoesNotExist:
                        pass
            
            class TaskExecutionLogViewSet(viewsets.ReadOnlyModelViewSet):
                queryset = TaskExecutionLog.objects.all()
                serializer_class = TaskExecutionLogSerializer
            

            from django.urls import include, path
            from rest_framework import routers
            from .views import ScheduledTaskViewSet, TaskExecutionLogViewSet
            
            router = routers.DefaultRouter()
            router.register(r'tasks', ScheduledTaskViewSet)
            router.register(r'logs', TaskExecutionLogViewSet)
            
            urlpatterns = [
                path('', include(router.urls)),
            ]
            

            from django.contrib import admin
            from django.urls import path, include
            
            urlpatterns = [
                path('admin/', admin.site.urls),
                path('api/', include('tasks.urls')),
            ]
            

            from celery import shared_task
            from .models import ScheduledTask, TaskExecutionLog
            import logging
            
            logger = logging.getLogger(__name__)
            
            @shared_task(bind=True, autoretry_for=(Exception,), retry_backoff=3, retry_kwargs={'max_retries': 3})
            def sample_task(self, task_id):
                try:
                    task = ScheduledTask.objects.get(id=task_id)
                    
                    # 模拟任务执行
                    result = f"任务 {task.name} 执行成功,时间:{str(self.request.time_start)}"
                    
                    # 记录执行日志
                    TaskExecutionLog.objects.create(
                        task=task,
                        status='success',
                        result=result
                    )
                    
                    logger.info(f"任务执行成功: {task.name}")
                    return result
                    
                except Exception as e:
                    # 记录错误日志
                    task = ScheduledTask.objects.get(id=task_id) if ScheduledTask.objects.filter(id=task_id).exists() else None
                    if task:
                        TaskExecutionLog.objects.create(
                            task=task,
                            status='failed',
                            error_message=str(e)
                        )
                    logger.error(f"任务执行失败: {str(e)}")
                    raise
            

            redis-server
            

            celery -A task_manager worker --loglevel=info --pool=prefork --concurrency=4
            

            celery -A task_manager beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler
            

            python manage.py runserver
            

            curl -X POST http://localhost:8000/api/tasks/ -d '{
                "name": "示例周期性任务",
                "task_type": "periodic",
                "task_function": "tasks.tasks.sample_task",
                "interval_seconds": 60,
                "is_active": true
            }' -H "Content-Type: application/json"
            

            curl http://localhost:8000/api/tasks/
            

            curl http://localhost:8000/api/logs/
            

            task_manager/
            ├── task_manager/
            │   ├── __init__.py
            │   ├── celery.py
            │   ├── settings.py
            │   ├── urls.py
            │   └── wsgi.py
            ├── tasks/
            │   ├── migrations/
            │   ├── __init__.py
            │   ├── admin.py
            │   ├── apps.py
            │   ├── models.py
            │   ├── serializers.py
            │   ├── tasks.py
            │   ├── urls.py
            │   └── views.py
            ├── manage.py
            └── db.sqlite3
            

            • 动态任务管理:通过 API 创建 / 更新 / 删除定时任务
            • 任务执行记录:自动记录任务执行结果和状态
            • 失败重试机制:任务失败时自动重试(最多 3 次)
            • 多种调度方式:支持周期性任务和一次性任务
            • 可视化管理:通过 Django Admin 界面管理定时任务

            • 添加任务参数支持,允许在创建任务时传递参数
            • 实现任务暂停 / 恢复功能
            • 添加任务优先级队列配置
            • 集成监控系统(如 Prometheus+Grafana)
            • 实现任务执行结果的异步通知(邮件、短信等)

            这个实现提供了一个完整的 Django+Celery 定时任务系统,支持动态管理和监控,可直接用于生产环境。

            以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。

            您可能感兴趣的文章:

            • django celery定时任务实战详解
            • 如何使用celery进行异步处理和定时任务(django)
            • Django中使用Celery执行定时任务问题
            • django中celery的定时任务使用
            • django-celery-beat搭建定时任务的实现
            • Django初步使用Celery处理耗时任务和定时任务问题

            站内搜索