This is the 22nd day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Hello ~ I’m Milo! I am building an open source interface testing platform from 0 to 1, and I am also writing a complete tutorial corresponding to it. I hope you can support it. Welcome to pay attention to my public number test development pit goods, get the latest article tutorial!

review

In the last section, we made pre-conditional replication available. This section is supposed to be about sending emails.

But before I do, I have a very serious question.

configuration

Our test platform will be connected to YAPI and other systems in the future. There has to be a place to maintain the data.

Including sender email, password, and so on.

However, these data are usually shared globally. If put in DB, it is useless, because there is only one data. If put in Redis, the data may be lost.

The blogger wasn’t sure where to put it and decided to put it in a configuration.json configuration file.

But it’s not good to read files too often. In addition, there will be many workers online, and there may be conflicts.

Think of the redis we used before, isn’t that where it comes in?

Write generic cache methods

Before we do that, let’s think about why we wrote this generic caching approach:

We get the data in two parts, get and set. In combination with caching, we can write pseudocode like this:

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

If we get the key, we return, if we don’t get the key, we update the data, we write the data to Redis, and we return data.

So what do we do when we modify the data?

def update_cache() :
    update(data)
    redis.delete(key)
Copy the code
  1. Update the data source first
  2. Delete cached data so that when you go down to fetch the cacheRetrieve dataAnd write to the cache

But do you think that this is a tedious process, and it’s something other than get and set, and every time we do that, we can decorateit.

Write the cache decorator

  • Method to connect to local Redis

    First we configure the connection information of Redis in config.py, then we write the client client, because it is the connection pool mode, so we have no problem using this client. (So I’m going to set it to property here)

  • Write RedisHelper

    The helper class has two decorators: cache reads (get) and up_cache updates (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) :
        Automatic cache decorator :param key: cached key: param expired_time: default key expiration time: 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)
                The cache already exists
                if data is not None:
                    return json.loads(data)
                Get the latest 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) :
        Param key: :return: """

        def decorator(func) :
            @functools.wraps(func)
            def wrapper(*args, **kwargs) :
                redis_key = RedisHelper.get_key(key)
                Get the latest data
                new_data = func(*args, **kwargs)
                Update data, delete cache
                RedisHelper.pity_redis_client.delete(redis_key)
                return new_data

            return wrapper

        return decorator
Copy the code

Here we basically according to the logic said before to do, in the future we fetch data method, just need to + the cache decorator in front of the method, can automatically get through with Redis. (Cache data if there is cache, real data if there is no cache)

Write a method for obtaining configuration files

We write configuration.json to the root directory:

import json
import os

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


class SystemConfiguration(object) :
    "" system Configuration ""

    @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 file not found, please check if configuration file has been deleted.")
            with open(filepath, mode="r", encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            raise Exception(F "Failed to obtain system Settings,{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 file not found, please check if configuration file has been deleted.")
            with open(filepath, mode="r", encoding='utf-8') as f:
                json.dump(config, f)
        except Exception as e:
            raise Exception(F "Failed to update system Settings,{e}")
Copy the code

Since configuration files are rarely updated, we set the expiration of the key to one day (it could be much longer).

This way, we can call get_config to get the system Settings, which contain our important sender information.

Test the

After starting the program, we go to query the key about configuration in Redis, and use our own client:

Test the expiration time again:

That’s it for today. Next, we’ll start our inspirational email (report notification) tour.