使用 django middleware 和 celery 隔離業務系統和積分系統的嘗試

遊戲類或是論壇類web應用,到後面不少都會有積分系統:像發成功一篇文章,回覆一條博客得多少積分這種。積分系統和不少的業務場景都有關係,可是和具體的用戶請求沒有關係。應該將積分系統和具體的業務程序進行隔離,以下降耦合度。筆者要開發的積分系統不須要具備實時性,因此打算用異步的方式來實現積分計算程序。 實現方案:html

  • 使用celery實現積分計算和驗證程序
  • 在django middleware 中準備好參數,並異步調用積分系統

django middleware 簡介

Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level 「plugin」 system for globally altering Django’s input or output. 以上摘自django官網 我的以爲 django middleware 是一種面向方面編程(AOP)思想的實現: 對全部的views程序提供統一的無感的處理。實際場景中可用middleware來統一response輸出格式,統一異常處理,還有統一在輸入中加入登陸驗證信息等。 新版的自定義middleware方式很簡單:python

  1. 新建python文件
class TestMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # 這後面寫的代碼對中間件進行初始化,只執行一次

    def __call__(self, request):
        # 這裏寫的代碼在調用view的方法以前執行,能夠對request進行處理

        response = self.get_response(request)

        # 這裏寫的代碼在調用view方法以後執行,能夠對response的返回值進行統一格式處理等
        
        return response
複製代碼
  1. 寫好middleware邏輯後,將這個類放到django的settings文件中
# 注意: django調用middle時按照這裏的排列順序來 裝飾 的,越前面的裝飾的越外層,即:
# 排在越前面的,在調用views方法前越早被執行,調用views方法後越晚被執行
# 排在越後面的,在調用views方法前越晚被執行,調用views方法後越早被執行
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'your middleware path',
]
複製代碼

寫好這些後,這個middleware就完成了 django middlewaregit


django 集成 celery

Celery - Distributed Task Queue Celery is a simple, flexible, and reliable distributed system to process vast amounts of messages, while providing operations with the tools required to maintain such a system. It’s a task queue with focus on real-time processing, while also supporting task scheduling. 以上信息摘自celery官網 celery是用python語言開發的分佈式任務隊列,可用於任務的同步處理(接收任務處理返回結果),也可用於異步處理(不接收返回結果)。在django中處理異步任務(發郵件;消息推送等)時,celery是個很好的選擇。 運行celery須要中間件,這裏使用rabbitMQ,下面簡單介紹如何集成。github

安裝rabbitMQ

  1. 執行安裝 brew install rabbitmq
  2. 設置環境變量 PATH=$PATH:/usr/local/sbin
  3. 啓動 sudo rabbitmq-server -detached
  4. 設置用戶

$ sudo rabbitmqctl add_user myuser mypassword $ sudo rabbitmqctl add_vhost myvhost $ sudo rabbitmqctl set_user_tags myuser mytag $ sudo rabbitmqctl set_permissions -p myvhost myuser ".*" ".*" ".*" 設置好後在celery中直接配置 'amqp://myuser:mypassword@localhost:5672/myvhost'就能夠用了web

  1. 啓停 啓動: sudo rabbitmq-server 之後臺運行方式啓動: $ sudo rabbitmq-server -detached 中止: $ sudo rabbitmqctl stop Never use kill (kill(1)) to stop the RabbitMQ server(忌直接殺進程!!!) 詳細操做見rabbit官網

安裝celery

celery 是用python開發的,能夠直接用pip安裝 $ pip install -U Celery 更多詳細安裝選項見celery官網django

django集成celery

django集成celery是將celery的配置嵌入到django的settings文件中,更重要的,是celery執行任務的時候,能直接使用django項目的運行環境。編程

  • 配置settings文件:上面的rabbitMQ安裝設置好後,在settings中直接引入 CELERY_BROKER_URL = 'amqp://myuser:mypassword@localhost:5672/myvhost'
  • 編寫celery執行入口文件celery.py文件放在settings的同級目錄下
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery


# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_app.settings')

app = Celery('msl')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))
複製代碼
  • 編寫自定義任務 在自定義的app的一級目錄下面新建python文件,名稱爲 tasks.py用於構建自定義的任務。
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from celery import shared_task


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


@shared_task
def mul(x, y):
    return x * y


@shared_task
def xsum(numbers):
    return sum(numbers)
複製代碼
  • 啓停celery 要後臺運行方式啓動的,可使用supervisord等管理程序進行啓停管理。非後臺方式啓動爲:celery -A proj worker -l info ;proj 爲celery所在目錄的目錄名,不作修改的話就是項目名字。 這樣啓動的使用ctrl + c中止就能夠。 django集成celery官方示例

積分系統實現嘗試

思路

  • django middleware中,在調用業務處理得到response後,能夠經過訪問request和response中的數據肯定:
  1. 本次調用的具體是哪一個業務(request的METHOD和path一塊兒來肯定)
  1. 對應的用戶的信息(須要事先在中間件中將用戶信息加入request)
  2. 調用是否成功(response的狀態或是定義的返回碼等)
  3. 返回的數據(從response中獲取)
  • 制定任務規則,在celery task中將對接口的調用抽象成一次任務,符合要求的即爲完成某一件任務,並對完成的任務作記錄。

簽到接口調用:調用完成後,在task中判斷,若是這次簽到調用成功,則記錄該時間點上完成某個用戶完成一次簽到任務session

  • 制定針對任務的積分獎勵規則,在規定時間內完成多少次任務就能夠得到積分。並用剛完成的任務對應獎勵規則,記錄該項規則的任務完成進度,任務完成的記錄積分獲取記錄。

將獎勵規則制定爲: 完成一次簽到任務能夠得到1點積分,連續完成十次簽到任務能夠額外得到2點積分。則這次簽到任務完成後,會對應去判斷這兩條規則。第一條確定直接知足,記錄下該條規則下籤到獲取積分進度爲完成,並記錄積分獲取記錄。第二條若是不知足,記錄下該規則下調到積分獲取進度爲未完成,未完成的就沒有積分獲取記錄了。app

庫表設計(精簡版)

from django.db import models


class TaskConfig(models.Model):
    """任務配置表 task_type 任務類型 task_desc 任務描述 method 方法(GET, POST, ...) interface_name 接口名 id_group_name 業務主鍵分組名字(正則式中的分組名稱) status 狀態 (編輯中, 使用中, 廢棄) created_at 建立時間 deleted_at 刪除時間 updated_at 修改時間 """
    

class UserTaskRecord(models.Model):
    """用戶任務記錄表 user 用戶 task 任務類型(外鍵) business_id 業務主鍵(建立博客的就是哪條博客的ID) created_at 建立時間 updated_at 修改時間 delete_at 刪除時間 """
    
    
class ScoreRule(SoftDeleteModel):
    """積分規表 task_type 任務類型 score_type 積分規則類型 score_desc 積分規則描述 statistical_period 統計週期(天天,每週,每個月,每一年,無週期,...) required_number_of_times 所需次數 number_limit_all 獲取人數上限 start_time 規則生效時間 end_time 規則截止時間 status 規則狀態(編輯中和已生效) can_repeat 任務內容是否可重複(默認爲可重複) created_at 建立時間 deleted_at 刪除時間 updated_at 修改時間 """


class UserScoreInfo(SoftDeleteModel):
    """用戶積分信息表 user 用戶 achievement_type 積分規則類型(外鍵) required_number 所需任務量 achievement_amount_now 當任務就量 achieved 達成標誌 created_at 建立時間 deadline 計算截止時間 updated_at 修改時間 deleted_at 刪除時間 """
    

class ScoreRecord(SoftDeleteModel):
    """積分記錄 profile 帳戶 user 用戶 serial_number 流水號 trade_amount 積分 amount_before_trade 計算前帳戶積份量 amount_after_trade 計算後帳戶積份量 business_type 業務類型(積分規則描述) score_info 積分信息(外鍵) location 地點 country 國家 lang_type 語言 created_at 建立時間 updated_at 修改時間 deleted_at 刪除時間 """

複製代碼

到這裏一個簡陋的積分系統就基本完成了,不過這樣制定的規則會有不少限制,好比分享博客能夠得到積分這種,若是針對某個具體的博客分享後所得到積份量不一樣,這就須要更進一步的設計。異步

相關文章
相關標籤/搜索