学生成绩管理项目-番外篇(celery)

668 阅读3分钟

18-番外篇-celery插件_哔哩哔哩_bilibili

后端

仓库地址:gitee.com/huge-dream/…

使用

官方推荐的是用 pip

pip install dvadmin-celery

但这样不太好修改代码和学习,这里我们直接从仓库下载之后,放到backend/pluginsimage.png 如果使用官方推荐的pip install dvadmin-celery则不需要安装,会自动依赖包,如果手动配置,则需要安装依赖包,安装包的时候,需要注意版本,以下是我使用的依赖包和版本

django-celery-beat==2.2.1
tenant-schemas-celery==1.0.1
django-celery-results==2.2.0
eventlet==0.33.3

手动注册

# ********** 一键导入插件配置开始 **********
...
from dvadmin_celery.settings import *           # celery 异步任务
...
# ********** 一键导入插件配置结束 **********

迁移数据库

python3 manage.py makemigrations 
python3 manage.py migrate 
# 注意备份初始化信息
python3 manage.py init -y 

启动服务

mac/linux:
celery -A application.celery worker -B --loglevel=info

win:
需要安装: pip install eventlet,需要启动两个程序(worker + beat 顺序不分先后)
celery -A application.celery worker -P eventlet --loglevel=info
celery -A application.celery beat --loglevel=info

后端Bug

文件路径:plugins/dvadmin-celery/dvadmin_celery/views/task.py 注释掉这行代码

class PeriodicTasksSerializer(CustomModelSerializer):
    # crontab = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = PeriodicTask
        fields = '__all__'

时区问题:

  • 方案一,在settings.py修改配置
# CELERY_TIMEZONE = "Asia/Shanghai"  # celery 时区问题
# 修改成
NONE_TIMEZONE = "Asia/Shanghai"  # celery 时区问题
  • 方案二:在celery.py修改配置
app = Celery(f"application")
# 修改成
app = Celery(f"application",namespace="CELERY")

同时还要修改plugins/dvadmin-celery/dvadmin_celery/settings.py

if not hasattr(settings, 'BROKER_URL'):
    settings.BROKER_URL = f'{settings.REDIS_URL}/2'
# 修改成
if not hasattr(settings, 'CELERY_BROKER_URL'):
    settings.CELERY_BROKER_URL = f'{settings.REDIS_URL}/2'
  • 方案三:修改plugins/dvadmin-celery/dvadmin_celery/views/task.py
cron_data = {
    'minute': minute,
    'hour': hour,
    'day_of_week': week,
    'day_of_month': day,
    'month_of_year': month,
    'timezone':CELERY_TIMEZONE # 增加这个字段
}

自定义tasks

如果想在自己的app下面写异步任务,则需要在app目录下增加tasks目录,将所有的异步函数都写在这里,celery会查找INSTALLED_APPS 里面所有注册的app目录中的tasks目录,然后注册任务 如果想用dvadmin-celery的前端来调用异步任务,需要将任务的名称添加task__前缀

image.png

tasks

from application.celery import app

@app.task
def task__one():
    print("自定义task")
    return "自定义task"

views

    @swagger_auto_schema(operation_description='异步任务')
    @action(methods=['get'], detail=False)
    def async_task(self, request, *args, **kwargs):
        print(request)
        result = task__one.apply_async()
        data = result.get()
        print(data)
        return SuccessResponse(data=[], msg="获取成功")

前端

仓库地址:gitee.com/huge-dream/…

使用

也是使用手动配置的方式,将文件放到src\views\plugins目录下 image.png 如果出现这个错误 PMOV7P7_9K6{MFXBRO}4SH8.png 需要将src\views\plugins\dvadmin-celery-web\src\timingTask里面的index.js复制到 src\views\plugins\dvadmin-celery-web\src里面,并修改引用

import timingTask from './timingTask'; # 修改这里的引用

timingTask.install = (Vue) => Vue.component(timingTask.name, timingTask); // 注册组件

export default timingTask;

Cron介绍

django-celery-beat的Cron最小单位是分


class CrontabSchedule(models.Model):
    """Timezone Aware Crontab-like schedule.

    Example:  Run every hour at 0 minutes for days of month 10-15
    minute="0", hour="*", day_of_week="*",
    day_of_month="10-15", month_of_year="*"
    """

    #
    # The worst case scenario for day of month is a list of all 31 day numbers
    # '[1, 2, ..., 31]' which has a length of 115. Likewise, minute can be
    # 0..59 and hour can be 0..23. Ensure we can accomodate these by allowing
    # 4 chars for each value (what we save on 0-9 accomodates the []).
    # We leave the other fields at their historical length.
    #
    minute = models.CharField(
        max_length=60 * 4, default='*',
        verbose_name=_('Minute(s)'),
        help_text=_(
            'Cron Minutes to Run. Use "*" for "all". (Example: "0,30")'),
        validators=[validators.minute_validator],
    )
    hour = models.CharField(
        max_length=24 * 4, default='*',
        verbose_name=_('Hour(s)'),
        help_text=_(
            'Cron Hours to Run. Use "*" for "all". (Example: "8,20")'),
        validators=[validators.hour_validator],
    )
    day_of_week = models.CharField(
        max_length=64, default='*',
        verbose_name=_('Day(s) Of The Week'),
        help_text=_(
            'Cron Days Of The Week to Run. Use "*" for "all". '
            '(Example: "0,5")'),
        validators=[validators.day_of_week_validator],
    )
    day_of_month = models.CharField(
        max_length=31 * 4, default='*',
        verbose_name=_('Day(s) Of The Month'),
        help_text=_(
            'Cron Days Of The Month to Run. Use "*" for "all". '
            '(Example: "1,15")'),
        validators=[validators.day_of_month_validator],
    )
    month_of_year = models.CharField(
        max_length=64, default='*',
        verbose_name=_('Month(s) Of The Year'),
        help_text=_(
            'Cron Months Of The Year to Run. Use "*" for "all". '
            '(Example: "0,6")'),
        validators=[validators.month_of_year_validator],
    )

    timezone = timezone_field.TimeZoneField(
        default=crontab_schedule_celery_timezone,
        verbose_name=_('Cron Timezone'),
        help_text=_(
            'Timezone to Run the Cron Schedule on. Default is UTC.'),
    )

插件有点小bug,这是每分钟,且不能用?号 image.png