You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flask Cache时间范围复用问题:非时段无法读取历史缓存数据

解决Flask应用特定时段拉取数据+非时段复用缓存的问题

看起来你遇到的核心问题是缓存依赖用户访问维持,而非主动提前缓存,导致非时段如果很久没人访问接口就没数据可用。下面我给你一套完整的解决方案,结合定时任务主动预缓存+时段判断逻辑,完美解决你的需求:

核心思路

  1. 定时任务在目标URL停止返回数据前1分钟(也就是每天16:29)主动拉取并缓存最新数据,确保非时段有数据可用
  2. 在接口中加入时段判断
    • 允许时段内:优先实时拉取数据,失败则 fallback 到缓存
    • 非允许时段:直接返回预缓存的数据
  3. 缓存配置成长期有效(直到下一次定时任务更新),避免自动过期导致数据丢失

实现步骤

1. 安装依赖

首先安装需要的包:

pip install flask flask-caching apscheduler

2. 完整代码示例

from flask import Flask, jsonify
from flask_caching import Cache
from apscheduler.schedulers.background import BackgroundScheduler
import requests
from datetime import datetime

app = Flask(__name__)

# 配置缓存:用文件系统缓存,也可以换成Redis
app.config['CACHE_TYPE'] = 'FileSystemCache'
app.config['CACHE_DIR'] = './cache'
app.config['CACHE_DEFAULT_TIMEOUT'] = 86400  # 默认缓存1天,足够覆盖非时段

cache = Cache(app)

# 目标数据URL和时段配置
TARGET_URL = "你的指定数据URL"
# 允许实时拉取的时段:比如每天9:00到16:30
ALLOWED_START_HOUR = 9
ALLOWED_END_HOUR = 16
ALLOWED_END_MINUTE = 30

def fetch_and_cache_data():
    """拉取最新数据并缓存,供定时任务调用"""
    try:
        response = requests.get(TARGET_URL)
        response.raise_for_status()  # 检查请求是否成功
        data = response.json()
        cache.set('top_data', data)
        print(f"[{datetime.now()}] 成功缓存最新数据")
    except Exception as e:
        print(f"[{datetime.now()}] 缓存数据失败:{str(e)}")
        # 如果拉取失败,可以考虑保留旧缓存,不做操作

def is_in_allowed_time():
    """判断当前是否在允许实时拉取数据的时段内"""
    now = datetime.now()
    # 先判断小时:如果在9-15点,直接允许;如果是16点,需要分钟小于30
    if now.hour < ALLOWED_START_HOUR or now.hour > ALLOWED_END_HOUR:
        return False
    if now.hour == ALLOWED_END_HOUR and now.minute >= ALLOWED_END_MINUTE:
        return False
    return True

@app.route('/top')
def get_top_data():
    # 先尝试获取缓存数据
    cached_data = cache.get('top_data')
    
    # 判断当前是否在允许时段内
    if is_in_allowed_time():
        try:
            # 实时拉取最新数据
            response = requests.get(TARGET_URL)
            response.raise_for_status()
            real_time_data = response.json()
            # 更新缓存
            cache.set('top_data', real_time_data)
            return jsonify(real_time_data)
        except Exception as e:
            # 实时拉取失败,返回缓存数据(如果有的话)
            if cached_data:
                print(f"实时拉取失败,返回缓存数据:{str(e)}")
                return jsonify(cached_data)
            else:
                return jsonify({"error": "实时拉取失败且无缓存数据"}), 500
    else:
        # 非允许时段,直接返回缓存数据
        if cached_data:
            return jsonify(cached_data)
        else:
            return jsonify({"error": "无缓存数据,请在允许时段访问后重试"}), 500

# 初始化定时任务:每天16:29执行缓存操作
scheduler = BackgroundScheduler()
# 添加定时任务,每天16:29运行fetch_and_cache_data
scheduler.add_job(fetch_and_cache_data, 'cron', hour=16, minute=29)
scheduler.start()

if __name__ == '__main__':
    # 启动前先手动缓存一次(可选,避免第一天启动时无缓存)
    fetch_and_cache_data()
    app.run(debug=True)

关键细节解释

  • 定时任务:用APScheduler的cron触发器,每天精准在16:29执行缓存操作,确保在目标URL停更前拿到最新数据并保存
  • 缓存策略:设置默认超时为1天,足够覆盖非时段(比如从16:30到第二天9:00),而且定时任务会每天更新缓存,不用担心数据过时
  • 时段判断逻辑:精确到分钟,确保在16:30之后不再尝试实时拉取,直接用缓存
  • 容错处理:实时拉取失败时会自动 fallback 到缓存,避免接口报错;非时段如果缓存不存在(比如第一次启动)会给出明确提示

测试建议

  1. 可以先修改定时任务的时间(比如改成当前时间+1分钟),测试是否会主动缓存数据
  2. 修改is_in_allowed_time的判断条件,模拟非时段,看是否返回缓存数据
  3. 关闭目标URL的服务,测试实时拉取失败时是否会返回缓存内容

这样配置后,即使几天没人访问/top接口,只要定时任务正常运行,非时段依然能返回最新的缓存数据,完美解决你现在的问题~

内容的提问来源于stack exchange,提问作者bkcollection

火山引擎 最新活动