celery詳解(使用django+celery實現異步及定時任務以及使用supervisor進行管理)

最近工作之餘,記錄一下自己的筆記,首先來介紹一下celery

(一)、爲什麼要使用celery,業務場景

1、我們平時工作中,經常會碰到一個視圖裏面寫了很多邏輯,導致裏面有一些很耗時的操作,比如發送郵件、短信之類的操作,這些我們一般是調用第三方sdk去做的,通常客戶端接收響應需要等待,降低了服務器的吞吐量及性能

2、服務器難免會有定時任務的需求,比如用戶數據更新,緩存清除等等

(二)、celery介紹

爲了解決以上問題,我們可以使用celery
Celery是一個功能完備即插即用的任務隊列。
celery適用異步處理問題,當發送郵件、或者文件上傳, 圖像處理等等一些比較耗時的操作,我們可將其異步執行,這樣用戶不需要等待很久,提高用戶體驗。 celery的特點是:
1、簡單,易於使用和維護,有豐富的文檔。
2、高效,單個celery進程每分鐘可以處理數百萬個任務。
3、靈活,celery中幾乎每個部分都可以自定義擴展。

celery主要通過消息進行通信,通常使用一個叫Broker(中間人)來協調client(任務的發出者)和worker(任務的處理者). clients發出消息到隊列中,broker將隊列中的信息派發給worker來處理。

以下是某網站截圖,圖文表達更清楚一些
在這裏插入圖片描述
Celery需要一種解決消息的發送和接受的中間裝置叫做消息中間人。
本文使用的是redis來做中間人,django+celery+redis來實現簡單的異步和定時

話不多說,直接上代碼,代碼中都上了註釋

我的目錄結構
在這裏插入圖片描述
config.py

# import re
# from datetime import timedelta
from celery.schedules import crontab
from kombu import Queue
from celery_tasks.main import app

# 配置代理人,指定代理人將任務存到哪裏,這裏是redis的14號庫
broker_url = 'redis://127.0.0.1:6379/14'

# celery worker的併發數,默認是服務器的內核數目,也是命令行-c參數指定的數目
# CELERYD_CONCURRENCY = 8
worker_concurrency = 8

# celery worker 每次去BROKER中預取任務的數量-
worker_prefetch_multiplier = 4

# 每個worker執行了多少任務就會死掉,默認是無限的,釋放內存
worker_max_tasks_per_child = 200

# 任務結果保存時間
worker_task_result_expires = 60 * 60 * 2

# 非常重要,有些情況下可以防止死鎖
worker_force_execv = True

# 任務發出後,經過一段時間還未收到acknowledge , 就將任務重新交給其他worker執行
worker_disable_rate_limits = True

# 讀取任務結果一般性能要求不高,所以使用了可讀性更好的JSON
worker_result_serializer = "json"

# CELERY_TASK_DEFAULT_QUEUE = "default" # 默認隊列
worker_task_default_queue = "default"

task_queues = (
    Queue("default", routing_key="default"),
    Queue("base", routing_key="base.#"),
)

task_routes = {
  
    # res = tasks.test.apply_async(queue='default', routing_key='default')
    # 以上如果指定隊列執行,則下列指定方式失效
    "test": {'queue': 'base', 'routing_key': 'base.info'},
    # "test1": {'queue': 'base', 'routing_key': 'base.test'},
}
# 定義默認隊列和默認的交換機routing_key
task_default_queue = 'default'
task_default_exchange = 'default'
task_default_routing_key = 'default'

# 設置時區,默認UTC
timezone = 'Asia/Shanghai'

main.py

import os, logging
from datetime import timedelta
from config import settings
from celery import Celery

logger = logging.getLogger(settings.LOGGER_DEVICE_MANAGE)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
# 創建celery應用
app = Celery('test')

# 導入celery配置
app.config_from_object('celery_tasks.config')

# 自動註冊celery任務
# 在指定的包中找tasks.py文件,在這個文件中找@app.task的函數,當做任務
# app.autodiscover_tasks()  # 自動

# 定時任務需要添加
app.autodiscover_tasks(['celery_tasks.base_info'])
# # 在出現worker接受到的message出現沒有註冊的錯誤時,使用下面一句能解決
imports = ("tasks",)


最基本的配置已經完成
然後關於任務的邏輯編寫,我們可以在celery_tasks下面新建一個文件夾,叫base_info,再在base_info下面新建一個任務tasks.py,然後需要執行什麼任務直接在tasks.py裏面寫邏輯,這裏舉例是微信模板消息通知

import logging

from celery_tasks.main import app
# from util.sql_query import sql_query
from config import settings

from util import wechat

logger = logging.getLogger(settings.LOGGER_DEVICE_MANAGE)

@app.task(name='test')
def test():
    msg_ob = wechat.WechatAssistantMsg()
    res = msg_ob.send_msg(['33742'], '<a href="http://www.baidu.com">異步任務執行</a>')
    logger.info(res)

然後一定要記得啓動celery,這個是獨立啓動的
切記在celery_tasks目錄的上級目錄下啓動
命令celery -A celery_tasks.main worker -B -l info --beat (默認是啓動定時任務及異步任務)
在這裏插入圖片描述
我們看到celery已經啓動了,接下來我們啓動django,在django中編寫view.py
在這裏插入圖片描述
然後我們通過postman調用這個test接口,就可以看到celery控制檯輸出任務信息,執行成功
在這裏插入圖片描述

定時任務的配置

在config.py中只需添加以下代碼

from celery.schedules import crontab
# 設置定時任務
app.conf.beat_schedule = {
    "test_task": {
        "task": "test",
        "schedule": crontab(hour=11, minute=28),# 每天的11點28分執行一次任務
    }
}

其中的"task": “test”, test爲你需要執行的函數(任務)名
在這裏插入圖片描述
完成

使用supervisor管理celery

其中supervisor配置如下

[program:celery_worker]
command=/root/install/server/bin/celery -A celery_tasks.main worker -B -l info --beat

directory=/root/data/system/server_system
user=root
numprocs=1
stdout_logfile=/root/data/supervisor_celery.log

autorestart=true
startsecs=10
redirect_stderr=true
loglevel=info
redirect_stderr = true  ; 把 stderr 重定向到 stdout,默認 false


; Need to wait for currently executing tasks to finish at shutdown.
; Increase this if you have very long running tasks.
stopwaitsecs = 600

; Set Celery priority higher than default (999)
; so, if rabbitmq is supervised, it will start first.
priority=1000

然後重啓supervisor即可,我們可以通過supervisorctl客戶端看到多了一個任務進程
在這裏插入圖片描述
supervisor報錯可以結合我上一篇文章

如有任何疑問,歡迎留言

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