Django 使用定时任务的多种姿势对比

写在前面:
最近由于工作原因,不得不使用 Windows 系统进行 Django 开发工作,然后原来使用的django-crontab插件没办法在Windows系统上面进行定时任务。因此又想了其他方式来实现定时任务。下面就来说说这些方案的优缺点。
首先贴上我的目录结构
Django 使用定时任务的多种姿势对比_第1张图片

1、使用django-crontab插件来实现定时任务

1.1、安装插件

pip install django-crontab

1.2、使用插件

在settings.py INSTALLED_APPS引入app

INSTALLED_APPS = [
    ...
    'django_crontab'
]

在settings.py中配置定时任务,增加一下代码

# 定时任务
'''
*    *    *    *    * :分别表示 分(0-59)、时(0-23)、天(1 - 31)、月(1 - 12) 、周(星期中星期几 (0 - 7) (0 7 均为周天))
crontab范例:
每五分钟执行    */5 * * * *
每小时执行     0 * * * *
每天执行       0 0 * * *
每周一执行       0 0 * * 1
每月执行       0 0 1 * *
每天23点执行   0 23 * * *
'''
CRONJOBS = [
    ('*/1 * * * *', 'base.crontabs.confdict_handle', ' >> /tmp/logs/confdict_handle.log'), # 注意:/tmp/base_api 目录要手动创建
]

1.3、编写定时任务方法

在本例中是在apps/base/crontabs.py中增加的定时任务

from .models import ConfDict # base内的一个model,定时任务多数用来操作数据库,因此给一个示例
import datetime

# 定时任务 
def confdict_handle():
    try:
    	objs = CondDict.objects.all()
    	print(obj)
        loca_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print('本地时间:'+str(loca_time))
    except Exception as e:
        print('发生错误,错误信息为:', e)

1.4、如何使用&运行

开启定时器

python manage.py crontab add  

查看开启的定时器

python manage.py crontab show  

关闭定时器

python manage.py crontab remove  

1.5、优缺点

优点:
简单、方便、易于管理
和django服务是分离的,不会影响到django对外提供的web服务。
缺点:
无法在Windows平台上运行
就算在Linux系统上,也可能出现运行了没有效果的消息,至今未知原因。

2、使用django-apscheduler插件实现定时任务

2.1、安装插件

pip install django-apscheduler

2.2、使用插件

修改settings.py增加以下代码

INSTALLED_APPS = (
  ...
  "django_apscheduler",
)

2.3、迁移数据库

因为django-apscheduler会创建表来存储定时任务的一些信息,所以将app加入之后需要迁移数据

python manage.py migrate

2.4、完整示例 在views.py中增加你的定时任务代码

注意:如果在其他文件中添加代码是没有效果的

from apscheduler.schedulers.background import BackgroundScheduler # 使用它可以使你的定时任务在后台运行
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
import time
'''
date:在您希望在某个特定时间仅运行一次作业时使用
interval:当您要以固定的时间间隔运行作业时使用
cron:以crontab的方式运行定时任务
minutes:设置以分钟为单位的定时器
seconds:设置以秒为单位的定时器
'''

try:
    scheduler = BackgroundScheduler()
    scheduler.add_jobstore(DjangoJobStore(), "default")

    @register_job(scheduler, "interval", seconds=5)
    def test_job():
        # 定时每5秒执行一次
        print(time.strftime('%Y-%m-%d %H:%M:%S'))

    register_events(scheduler)
    # 启动定时器
    scheduler.start()
except Exception as e:
    print('定时任务异常:%s' % str(e))

2.6、如何使用&运行

apscheduler定时任务会跟随django项目一起运行因此直接启动django即可

python manage.py runserver

2.7、优缺点

优点:
简单、定时方式丰富
轻量
缺点:
定时任务会跟随django项目一起运行,会影响django对外提供的web服务
使用uwsgi线上运行时,很难启动apscheduler定时任务
按照文档上的设置--enable-threads依然没有正常启动,具体原因未知,也查了很多方法,都没有解决。并且也不建议将定时任务和uwsgi放在一起运行,这样定时任务在运行过程中可能会影响uwsgi的服务。

3、使用Celery插件实现定时任务

3.1、安装依赖

本例建立在认为你已经知道如何使用Celery实现异步任务的基础上,需要学习的请移步Django使用Celery
本例使用redis作为Borker和backend

pip install -U "celery[redis]"

3.2、使用插件

修改settings.py 增加以下代码

....
# Celery配置
from kombu import Exchange, Queue
# 设置任务接受的类型,默认是{'json'}
CELERY_ACCEPT_CONTENT = ['application/json']
# 设置task任务序列列化为json
CELERY_TASK_SERIALIZER = 'json'
# 请任务接受后存储时的类型
CELERY_RESULT_SERIALIZER = 'json'
# 时间格式化为中国时间
CELERY_TIMEZONE = 'Asia/Shanghai'
# 是否使用UTC时间
CELERY_ENABLE_UTC = False
# 指定borker为redis 如果指定rabbitmq CELERY_BROKER_URL = 'amqp://guest:guest@localhost:5672//'
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0'
# 指定存储结果的地方,支持使用rpc、数据库、redis等等,具体可参考文档 # CELERY_RESULT_BACKEND = 'db+mysql://scott:tiger@localhost/foo' # mysql 作为后端数据库
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'
# 设置任务过期时间 默认是一天,为None或0 表示永不过期
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24
# 设置worker并发数,默认是cpu核心数
# CELERYD_CONCURRENCY = 12
# 设置每个worker最大任务数
CELERYD_MAX_TASKS_PER_CHILD = 100
# 指定任务的位置
CELERY_IMPORTS = (
    'base.tasks',
)
# 使用beat启动Celery定时任务
# schedule时间的具体设定参考:https://docs.celeryproject.org/en/stable/userguide/periodic-tasks.html
CELERYBEAT_SCHEDULE = {
    'add-every-10-seconds': {
        'task': 'base.tasks.cheduler_task',
        'schedule': 10,
        'args': ('hello', )
    },
}
...

3.3、编写定时任务代码

在本例中是在apps/base/tasks.py中增加的定时任务

# Create your tasks here
from __future__ import absolute_import, unicode_literals
from celery import shared_task
import time

@shared_task
def cheduler_task(name):
    print(name)
    print(time.strftime('%X'))

3.4、如何使用&运行

启动定时任务beat

celery -A dase_django_api beat -l info

启动Celery worker 用来执行定时任务

celery -A dase_django_api worker -l -l info 

注意:这里的 dase_django_api 要换成你的Celery APP的名称

3.5、优缺点

优点:
稳定可靠、管理方便
高性能、支持分布式
缺点:
实现复杂
部署复杂
非轻量级

4、自建代码实现定时任务

4.1、创建定时任务

在apps/base下创建一个文件名为schedules.py;键入一下内容

import os, sys, time, datetime
import threading
import django
base_apth = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# print(base_apth)
# 将项目路径加入到系统path中,这样在导入模型等模块时就不会报模块找不到了
sys.path.append(base_apth)
os.environ['DJANGO_SETTINGS_MODULE'] ='base_django_api.settings' # 注意:base_django_api 是我的模块名,你在使用时需要跟换为你的模块
django.setup()
from base.models import ConfDict

def confdict_handle():
    while True:
        try:
            loca_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            print('本地时间:'+str(loca_time))
            time.sleep(10)
        except Exception as e:
            print('发生错误,错误信息为:', e)
            continue


def main():
    '''
    主函数,用于启动所有定时任务,因为当前定时任务是手动实现,因此可以自由发挥
    '''
    try:
        # 启动定时任务,多个任务时,使用多线程
        task1 = threading.Thread(target=confdict_handle)
        task1.start()
    except Exception as e:
        print('发生异常:%s' % str(e))

if __name__ == '__main__':
    main()

4.2、如何使用&运行

直接运行脚本即可

python apps/base/schedules.py

4.3、优缺点

优点:
自定义
高度自由
缺点:
过于简单
当任务过多时,占用资源也会增加

你可能感兴趣的:(Django)