Yuanlin Lin

Blog

帶你用 Zeabur 部署 Django + Celery 任務佇列到 AWS

Yuanlin Lin 林沅霖

2024-05-22

在這篇教學文章中,我將示範如何從零開始初始化一個 Django 專案,並且加入 Celery 進行異步任務處理,最後使用 Zeabur 將最後的完成品部署到 AWS 雲端伺服器。

進階主題:今天這篇教學文章屬於 Python 系列的進階主題,建議對 Python 及 Django 已經有基礎知識及經驗的讀者閱讀。

Python Celery 是一個分散式任務佇列(distributed task queue)的工具,它允許你在應用程式中異步執行任務,並且可以將這些任務分發到多個工作者節點中執行,進而實現並行處理和負載平衡。

為什麼需要 Celery 呢?因為在現代的應用程式開發中,有許多任務是耗時的或需要執行於背景中,例如寄送郵件、處理圖像、生成報告等等。若將這些任務直接放在主應用程式中執行,會阻塞主線程並降低應用程式的性能和響應速度。Celery 的出現解決了這個問題,它讓開發者可以將這些耗時的任務委託給 Celery 來執行,從而保證了主應用程式的順暢運行,同時也提高了應用程式的可擴展性和靈活性。

以下是一些 Celery 的使用場景:

  1. 非同步任務處理:例如在網站後端處理用戶上傳的文件,或是定期爬取網站數據等。

  2. 計算密集型任務:例如圖像處理、數據轉換、機器學習模型訓練等。透過 Celery,這些任務可以在後台進行,不影響用戶體驗。

  3. 集群任務分發:當應用程式需要處理大量任務時,可以將這些任務分發到多個節點上執行,從而提高處理速度和系統的容量。

  4. 定時任務調度:Celery 提供了方便的定時任務調度功能,可以設置定時執行某些任務,例如每天凌晨執行數據備份任務、每小時生成報告等。

為了簡化文章,我們今天的示範以「開發一個數學網站 mathsite」為例子,然後在「計算機 calculator」中建立一個「加法計算 add」的非同步任務。

先別急著吐槽!雖然加法計算是一個超快就能完成的動作,但為了模擬他是一個耗時的任務,我們在程式碼加入 sleep 20 假裝這是一個需要花費 20 秒才能完成的任務 XD

創建專案及虛擬環境

首先我們先在電腦上建立一個資料夾:

mkdir mathsite cd mathsite

然後,為你的專案創建一個虛擬環境以隔離依賴。

python -m venv venv source venv/bin/activate # 對於 Windows,使用 `venv\Scripts\activate`

然後記得把虛擬環境加入到 .gitignore 檔案裡面:

.gitignore:

venv

安裝 Django 和 Celery

接下來,安裝 Django 和 Celery 以及 Redis(我們將使用 Redis 作為 Celery 的 broker)。

pip install django celery redis

創建 Django 專案

使用 Django 命令行工具創建一個新的 Django 專案。

django-admin startproject mathsite .

創建 Django 應用

創建一個新的 Django 應用,我們將在這個應用中添加 Celery 任務。

python manage.py startapp calculator

配置 Django 專案

將新的應用添加到 INSTALLED_APPS 中。

mathsite/settings.py:

INSTALLED_APPS = [ ... 'calculator', ]

配置 Celery

在你的 Django 專案目錄下創建一個名為 celery.py 的文件,並進行以下配置:

mathsite/celery.py:

from __future__ import absolute_import, unicode_literals import os from celery import Celery # 設置默認的 Django 設置模塊 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mathsite.settings') # 創建 Celery 應用 app = Celery('mathsite') # 使用 Django 的設定文件作為配置源 app.config_from_object('django.conf:settings', namespace='CELERY') # 自動發現任務模塊 app.autodiscover_tasks()

mathsite/__init__.py 中,導入並初始化 Celery 應用:

mathsite/init.py:

from __future__ import absolute_import, unicode_literals # 導入 Celery 應用 from .celery import app as celery_app # 將 Celery 應用暴露為模塊層級變量 __all__ = ('celery_app',)

配置 Celery 設定

因為 Celery 需要搭配 Redis 資料庫使用,所以我們可以先在 Zeabur 上部署一個 Redis 服務。

先建立一個專案:

npx @zeabur/cli project create

地區選擇 AWS 日本機房:

? Select project region  [Use arrows to move, type to filter]
  DigitalOcean - sgp1 (Enterprise Customers Only) (Singapore)
  Amazon Web Services - us-west-1 (California, United States)
  Amazon Web Services - ap-east-1 (Hong Kong)
  Amazon Web Services - eu-central-1 (Frankfurt, Germany)
> Amazon Web Services - ap-northeast-1 (Tokyo, Japan)
  Huawei Cloud - cn-east-3 (Shanghai, China (Beta))

然後就可以看到專案建立成功的訊息了:

INFO	Project pitids created
INFO	Project context is set to <pitids>

建立成功後,就可以部署 Redis 服務了:

npx @zeabur/cli service deploy --template=PREBUILT --marketplace-code=redis ✔ Service Redis created 🚀 https://dash.zeabur.com/projects/664c576eb6c2f12719418f66/services/664c5773b6c2f12719418f69

建立完成後我們就可以查看 Redis 的連接參數了:

npx @zeabur/cli service instruction --name=Redis

你應該會看到下面的輸出:

Command to connect to your Redis: redis-cli -h hkg1.clusters.zeabur.com -p 32724 -a NDoiHx6j305w7qdvVMAbp89S4W12hmuJ
Redis Connection String: redis://:NDoiHx6j305w7qdvVMAbp89S4W12hmuJ@hkg1.clusters.zeabur.com:32724
Redis password: NDoiHx6j305w7qdvVMAbp89S4W12hmuJ
Redis host: hkg1.clusters.zeabur.com
Redis port: 32724

第二行就是我們的 Redis 連接參數啦~

在 Django 的 settings.py 中添加 Celery 設定,使用你線上的 Redis 服務作為 broker 和結果後端:

mathsite/settings.py:

# Celery 設定 CELERY_BROKER_URL = '<你的 Redis 連接參數>/0' CELERY_RESULT_BACKEND = '<你的 Redis 連接參數>/0' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' CELERY_TIMEZONE = 'UTC' CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True

記得將 你的 Redis 連接參數 替換為你從 npx @zeabur/cli service instruction 指令拿回來的連線參數哦,後面加上 /0 代表 Redis 的預設資料庫。

創建 Celery 任務

在應用中創建一個名為 tasks.py 的文件,並添加計算兩個數字之和的示例任務。

calculator/tasks.py:

from celery import shared_task import time @shared_task def add(x, y): time.sleep(20) # 為了假裝這是一個耗時的任務,我們讓它睡 20 秒 return x + y

創建 View 來調用 Celery 任務並返回任務 ID

calculator/views.py 中創建一個 View 來調用 Celery 任務並返回任務 ID。

calculator/views.py:

from django.http import JsonResponse from calculator.tasks import add from celery.result import AsyncResult def add_view(request): x = int(request.GET.get('x', 0)) y = int(request.GET.get('y', 0)) task = add.delay(x, y) return JsonResponse({'task_id': task.id}) def task_status_view(request, task_id): task_result = AsyncResult(task_id) response = { 'task_id': task_id, 'status': task_result.status, 'result': task_result.result, } return JsonResponse(response)

10. 配置 URL

calculator/urls.py 中配置 URL 路由,指向剛才創建的 View。

calculator/urls.py:

from django.urls import path from . import views urlpatterns = [ path('add/', views.add_view, name='add_view'), path('status/<str:task_id>/', views.task_status_view, name='task_status_view'), ]

並在主項目的 urls.py 中包含應用的 URL。

mathsite/urls.py:

from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('calculator.urls')), ]

本地測試

現在,我們已經基本上把專案都準備好了!在部署到 AWS 之前,我們先來測試一下功能呢是否正常運行:

啟動 Celery Worker

在專案目錄中啟動 Celery worker:

celery -A mathsite worker --loglevel=info

啟動 Django 開發伺服器

在專案目錄中啟動 Django 開發伺服器:

python manage.py runserver

測試

  1. 發送一個計算請求:

    打開瀏覽器,訪問 http://localhost:8000/add/?x=8&y=4,你應該會看到返回一個任務 ID,如下所示:

    { "task_id": "fbe599bb-7cea-4544-8b9a-057e704991c3" }
  2. 檢查任務狀態:

    打開瀏覽器,訪問 http://localhost:8000/status/some-task-id,你應該會看到任務的狀態和結果,如下所示:

    { "task_id": "fbe599bb-7cea-4544-8b9a-057e704991c3", "status": "PENDING", "result": null }

    可以看到 PEDING 代表任務還在進行中,畢竟加法是一個需要花費 20 秒才能完成的任務 🤣

    如果我們等 20 秒再打開一次的話:

    { "task_id": "fbe599bb-7cea-4544-8b9a-057e704991c3", "status": "SUCCESS", "result": 12 }

    就可以看到任務完成了,且 result 也是正確的 4+8=12

這樣,你就完成了從零開始初始化 Django 專案並加入 Celery 的過程,並且可以在本地測試你的 Celery 任務。

部署到線上

完成了本地測試以後,現在我們可以開始把專案部署到雲端了~

導出套件列表

首先,記得先把套件列表導出:

pip freeze > requirements.txt

部署服務

接下來,我們需要把 Django 和 Celery 分別部署為兩個獨立運行的服務,一個叫做 django 服務,另一個叫做 celery 服務。

雖然這兩個服務的程式碼是相同的,但 celery 服務需要使用不一樣的啟動指令,所以我們可以在專案的根目錄加入一個 zbpack.celery.json 檔案:

zbpack.celery.json:

{ "start_command": "celery -A mathsite worker --loglevel=info" }

然後部署:

npx @zeabur/cli deploy --create --name=django

然後再部署一次:

npx @zeabur/cli deploy --create --name=celery

現在我們的專案裡面應該有 redis, djangocelery 三個服務了,我們也可以去 Zeabur 的 dashboard 檢查看看:

綁定網域

最後,幫 Django 綁定一個可以從外網訪問的網域:

npx @zeabur/cli domain create ? Select a service django ? Is this a generated domain? Yes ? The subdomain part of zeabur.app: django-celery INFO Domain django-celery.zeabur.app added

這樣就綁定好了,注意不要綁定到錯誤的服務上喔,必須把域名綁定在 Django 服務否則是打不開的。

不過我們如果打開剛剛綁定的網域,你可能會看到這個錯誤頁面:

這是因為我們沒有把剛剛綁定的網域加入到 Django 的 ALLOWED_HOSTS 中,所以我們只要修改一下 mathsite/settings.py 裡面的內容,把

ALLOWED_HOSTS = []

改成

ALLOWED_HOSTS = ["django-celery.zeabur.app"]

然後重新部署一次(記得不要選錯服務,要選 django 哦):

npx @zeabur/cli deploy

就部署好了~

線上環境測試

這次,我們可以改用 curl 的方式進行線上環境的測試:

curl "https://django-celery.zeabur.app/add/?x=88&y=77" { "task_id": "a86a0914-42db-47f2-88b0-53a3a8b09cb0" }

任務啟動以後,等 20 秒再取得結果:

curl "https://django-celery.zeabur.app/status/a86a0914-42db-47f2-88b0-53a3a8b09cb0/" { "task_id": "a86a0914-42db-47f2-88b0-53a3a8b09cb0", "status": "SUCCESS", "result": 165 }

結語

這篇文章演示了如何從頭開始初始化一個 Django 專案,並添加 Celery 進行異步任務處理,最後使用 Zeabur 部署到 AWS 雲端伺服器上。我們從建立專案、安裝必要的套件,到配置 Celery、創建任務和 View,再到本地測試和線上部署,一步步地帶大家完成了整個流程。

透過這篇文章,不僅可以學到如何使用 Celery 來處理耗時的任務,從而提高應用程式的性能和響應速度。同時,通過部署到雲端伺服器上,讀者還可以學到如何使用 Zeabur 平台來輔助部署和管理應用程式,使整個開發過程更加順利和高效。

希望這篇文章能夠幫助到同學們更好地理解 Django 和 Celery 的使用,並且學會如何將自己的應用程式部署到線上環境中。如果這篇文章有幫助到你,可以在下面幫我按個愛心,以及留言告訴我你的想法。

如果你在跟著教學操作的途中遇到的任何問題,或是沒辦法順利的部署到 AWS 雲端,也歡迎來 Zeabur 的 Discord 頻道 找我喔!

有獎問卷調查

僅需要三分鐘,立即填寫 台灣開發者雲端部署習慣調查 問卷,幫助 Zeabur 改善使用者體驗,獲得價值 $150 台幣的免費雲端資源使用額度!

分享你的看法

暫無留言,你可以成為第一個留言的人!

author-avatar

關於作者

Yuanlin Lin 林沅霖

台灣桃園人,目前就讀浙江大學,主修計算機科學與技術,同時兼職外包全端開發工程師,熱愛產品設計與軟體開發。