close

Python Django 實作:Django + Celery + Redis 異步執行任務

一、概要:

為了增進使用者的體驗,常常會需要使用異步的方式來處理任務

可以使用Celery在後台異步運行一段程式,讓你的應用程式可以繼續響應客戶端的請求

例如發送信件不使用異步更新,就可能要稍等幾秒鐘將信件寄出,使用者才能繼續操作

如果使用Celery異步更新的話,發送信件則會在後台異步運行,使用者不需等待即可繼續操作

而這次,我則是要使用Celery在異步運行爬蟲程式,幫助我在後台定期爬取資料

二、準備:

1.安裝 Celery

(1)在windows安裝 Celery

在Windows 安裝 Celery 不支援4.0以上的版本

所以這裡安裝3.18版本

打開Django專案,並使用pip安裝Celery

pip install celery==3.1.18

(2)在 Linux 安裝 Celery

在 Linux 安裝 Celery

pip3 install celery

 

 

2.安裝 Redis

(1)在windows安裝 Redis

此github 下載windows適用的Redis 的msi檔案,並安裝

安裝後可以開啟工作管理員→服務,查看是否有正確運行

3.JPG

將下列代碼添加至Django專案的<settings.py>

#redis
BROKER_URL = 'redis://localhost:6379' 
CELERY_RESULT_BACKEND = 'redis://localhost:6379' 
CELERY_ACCEPT_CONTENT = ['application/json'] 
CELERY_TASK_SERIALIZER = 'json' 
CELERY_RESULT_SERIALIZER = 'json' 
CELERY_TIMEZONE = 'Asia/Taipei'

測試Celery是否正確安裝,請在專案環境下輸入以下指令:

celery -A 專案目錄 worker -l info

我的專案目錄名稱為savemoney,以下是我的運行結果

4.JPG

用ctrl+c退出,並輸入以下代碼確認調度任務程序是否已經準備完成:

celery -A 專案目錄 beat -l info

我的專案目錄名稱為savemoney,以下是我的運行結果

5.JPG

(2)在Linux安裝 Redis

1.安裝

$ sudo apt-get update 
$ sudo apt-get install redis-server

啟動 redis-server :$ redis-server

查看 redis :$ redis-cli

2.使用 django-redis

在虛擬環境中輸入指令進行安裝: pip3 install django-redis

將下列代碼添加至Django專案的<settings.py>

#redis
CELERY_BROKER_URL = 'redis://localhost:6379'
#: Only add pickle to this list if your broker is secured
CELERY_ACCEPT_CONTENT = ['json']
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_TASK_SERIALIZER = 'json'
CELERY_ENABLE_UTC = True
CELERY_TIMEZONE = 'Asia/Taipei'

三、使用Celery

1.在Windos配置Celery 3.1.8

在專案目錄創建celery.py,並添加以下內容:

from __future__ import absolute_import 
import os 
from celery import Celery 
from django.conf import settings 
# set the default Django settings module for the 'celery' program. 
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '<mysite>.settings') 
app = Celery('<mysite>') 
 
# Using a string here means the worker will not have to 
# pickle the object when using Windows. 
app.config_from_object('django.conf:settings') 
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 
 
@app.task(bind=True) 
def debug_task(self): 
    print('Request: {0!r}'.format(self.request))

在專案根目錄的專案資料夾的__init__.py添加以下代碼:

from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app

在settings.py添加:

BROKER_URL = 'redis://localhost:6379' 
CELERY_RESULT_BACKEND = 'redis://localhost:6379' 
CELERY_ACCEPT_CONTENT = ['application/json'] 
CELERY_TASK_SERIALIZER = 'json' 
CELERY_RESULT_SERIALIZER = 'json' 
CELERY_TIMEZONE = 'Asia/Taipei'

2.在Linux配置Celery 4.2.1

在專案目錄創建celery.py,並添加以下內容:

# http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '<mysite>.settings')

app = Celery('<mysite>')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

在專案根目錄的專案資料夾的__init__.py添加以下代碼:

from __future__ import absolute_import, unicode_literals

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

__all__ = ['celery_app']

在settings.py添加:

# Celery settings
CELERY_BROKER_URL = 'redis://localhost:6379'
#: Only add pickle to this list if your broker is secured
CELERY_ACCEPT_CONTENT = ['json']
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_TASK_SERIALIZER = 'json'
CELERY_ENABLE_UTC = True
CELERY_TIMEZONE = 'Asia/Taipei'


3.Celery任務

接下來將一個基本函數做一個簡單的Celery任務

def add(x, y): 
    return x + y

導入Celery相關套件與使用裝飾器

from celery.decorators import task 

@task(name="sum_two_numbers") 
def add(x, y): 
    return x + y

接著就透過以下方式使用Celery異步執行:

add.delay(7, 8)

 

4.週期任務

在Django要執行Celery的目錄創建一個<task.py>文件

並添加以下套件,最後則是導入要執行的自訂函數與獲取應用名稱:

from celery.decorators import task 
from celery.task.schedules import crontab
from celery.decorators import periodic_task
from celery.utils.log import get_task_logger

from yourapp.crawler import *
logger = get_task_logger(__name__)  

接著添加裝飾器,這邊是設置每10分鐘運行一次,設置詳情可以參照此處

還有運行的任務名稱:

@periodic_task(  
    run_every=(crontab(minute='*/10')),
    name="some_task",  
    ignore_result=True  
)

最後則是添加任務:

def some_task():
    
    crawler() #此為調用的自訂函數名稱
    logger.info("crawled_momo")

 

5.本地運行

在Django和Redis運行的環境下

在虛擬環境的專案目錄運行Celery指令,每個指令都需要新開一個命令窗口獨立運行

我的專案目錄名稱為savemoney,以下為代碼:

celery -A savemoney worker -l info 
celery -A savemoney beat -l info

下圖兩圖我自己的爬蟲task運行後的情形:

有兩個task,一個為momo_task,一個為pchome_task:

7.JPG

8.JPG

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 ivankao 的頭像
    ivankao

    IvanKao的部落格

    ivankao 發表在 痞客邦 留言(0) 人氣()