后端
使用
官方推荐的是用 pip
pip install dvadmin-celery
但这样不太好修改代码和学习,这里我们直接从仓库下载之后,放到backend/plugins下
如果使用官方推荐的
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__前缀
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="获取成功")
前端
使用
也是使用手动配置的方式,将文件放到src\views\plugins目录下
如果出现这个错误
需要将
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,这是每分钟,且不能用?号