測試平臺系列(85) 把redis運用到實戰中

米洛丶發表於2021-11-30

大家好~我是米洛

我正在從0到1打造一個開源的介面測試平臺, 也在編寫一套與之對應的完整教程,希望大家多多支援。

歡迎關注我的公眾號測試開發坑貨,獲取最新文章教程!

回顧

上一節我們讓支援了前置條件複製功能。這一節本來打算給大家講講郵件的傳送。

但在此之前,我想了一個很嚴重的問題。

配置

我們的測試平臺,後續會接入yapi,接入其他系統。勢必會有一個地方去維護這些資料。

包括髮件人郵箱,密碼等等資料。

但這些資料又通常是全域性共享,如果放到db的話,很雞肋,因為資料只有1條,如果放到redis,有可能資料會丟。

博主也不知道放哪裡比較好,最後決定放到一個configuration.json的配置檔案裡面了。

但是頻繁讀取檔案,總歸是不好的。而且我們線上會有許多個worker,還可能會有衝突

想到我們之前拿捏過的redis,這不正是它的用武之地嗎?

編寫通用cache方法

在此之前,我們先思考一下為啥要寫這樣的通用快取辦法:

我們獲取資料,有2部分,分別為get和set。結合快取來看,我們可以寫出這樣的虛擬碼:

def get_cache():
    data = redis.get(key)
    if data is not None:
        return data
    data = get_data()
    redis.set(key, data)
    return data

就是這麼簡單的用法,如果key獲取到了,我們直接return,如果沒獲取到,我們更新資料,並把資料寫入redis,最後返回data。

那我們修改資料的時候怎麼做呢?

def update_cache():
    update(data)
    redis.delete(key)
  1. 先更新資料來源
  2. 刪除快取資料,這樣下去獲取快取的時候就會重新獲取資料並寫入快取

但大家有沒有覺得這個過程很繁瑣,而且屬於get和set之外的操作,每每有這種操作的時候,我們就可以把它裝飾器化。

編寫cache裝飾器

  • 連線本地redis的方法

    首先我們在config.py配置好redis的連線資訊,接著編寫client客戶端,因為它本身是連線池模式,所以我們一直用這個客戶端都沒問題。(所以我這裡把它設定為了property)

  • 編寫RedisHelper

    helper類含有2個裝飾器,cache負責讀取(get),up_cache負責更新(set)。

class RedisHelper(object):
    pity_prefix = "pity"
    pity_redis_client = PityRedisManager().client

    @staticmethod
    def get_key(key: str):
        return f"{RedisHelper.pity_prefix}:{key}"

    @staticmethod
    def cache(key: str, expired_time=3 * 60):
        """
        自動快取裝飾器
        :param key: 被快取的key
        :param expired_time: 預設key過期時間
        :return:
        """

        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                redis_key = RedisHelper.get_key(key)
                data = RedisHelper.pity_redis_client.get(redis_key)
                # 快取已存在
                if data is not None:
                    return json.loads(data)
                # 獲取最新資料
                new_data = func(*args, **kwargs)
                info = json.dumps(new_data)
                RedisHelper.pity_redis_client.set(redis_key, info, ex=expired_time)
                return new_data

            return wrapper

        return decorator

    @staticmethod
    def up_cache(key: str):
        """
        redis快取key,套了此方法,會自動執行更新資料操作後刪除快取
        :param key:
        :return:
        """

        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                redis_key = RedisHelper.get_key(key)
                # 獲取最新資料
                new_data = func(*args, **kwargs)
                # 更新資料,刪除快取
                RedisHelper.pity_redis_client.delete(redis_key)
                return new_data

            return wrapper

        return decorator

這裡我們基本上按照之前說的邏輯來做的,以後我們取資料的方法,只需要在方法前面+上cache裝飾器,即可自動跟redis打通。(有快取則取快取資料,無則取真實資料)

編寫配置檔案獲取方法

我們編寫configuration.json到根目錄:

這裡放郵件資訊,還有未來要規劃的yapi資訊

import json
import os

from app.middleware.RedisManager import RedisHelper
from config import Config


class SystemConfiguration(object):
    """
    系統配置
    """

    @staticmethod
    @RedisHelper.cache("configuration", 24 * 3600)
    def get_config():
        try:
            filepath = os.path.join(Config.ROOT, "configuration.json")
            if not os.path.exists(filepath):
                raise Exception("沒找到配置檔案,請檢查configuration檔案是否已經被刪除")
            with open(filepath, mode="r", encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            raise Exception(f"獲取系統設定失敗, {e}")

    @staticmethod
    @RedisHelper.up_cache("configuration")
    def update_config(config):
        try:
            filepath = os.path.join(Config.ROOT, "configuration.json")
            if not os.path.exists(filepath):
                raise Exception("沒找到配置檔案,請檢查configuration檔案是否已經被刪除")
            with open(filepath, mode="r", encoding='utf-8') as f:
                json.dump(config, f)
        except Exception as e:
            raise Exception(f"更新系統設定失敗, {e}")

由於配置檔案一般很少更新,所以我們把key的過期時間設為了1天(其實可以更久一點)。

這樣,我們呼叫get_config就可以拿到系統設定啦,裡面有我們們很重要的發件人資訊。

測試一下

啟動程式以後,我們去查詢redis中關於configuration的key,就用我們們自己寫的客戶端:

再測試下過期時間:

今天的內容就到這裡,下節正式開啟發郵件(報告通知)之旅。

相關文章