Django 使用定時任務的多種姿勢對比

寫在前面:
最近由於工作原因,不得不使用 Windows 系統進行 Django 開發工作,然後原來使用的django-crontab插件沒辦法在Windows系統上面進行定時任務。因此又想了其他方式來實現定時任務。下面就來說說這些方案的優缺點。
首先貼上我的目錄結構
在這裏插入圖片描述

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、優缺點

優點:
自定義
高度自由
缺點:
過於簡單
當任務過多時,佔用資源也會增加

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章