Flask - 后台重启缓存数据丢失

实验背景

为了缓解后台压力,在前端请求时添加一个缓冲队列用来缓存请求。但是,实验中发现flask框架会在修改代码逻辑内容后进行重启,导致缓存队列清空。为了解决这个问题,在队列清空时将队列中的请求持久化到本地存储中。由此,避免数据的丢失。
flask重启队列消失

代码框架

代码结构:

tree
.
├── bin
│   └── run.py
├── demo.py
├── log
└── stor
    ├── demo.py
    ├── __init__.py
    └── webapi.py

3 directories, 5 files
run.py
import sys
import os

app_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(app_root)
print(app_root)

from stor.webapi import app
from stor.demo import task_consumer

if __name__ == '__main__':
	# 启动一个守护线程,用来监测队列中的任务
    thr = task_consumer()
    app.run(debug = True, threaded = True, host = '0.0.0.0', port = 10800, use_reloader = True)
    thr.join()
webapi.py
from flask import Flask, request
app = Flask(__name__)

from demo import task_producer

@app.route('/demo', methods = ['GET'])
def put_task():
    tasks = request.values.getlist('tasks', int)
    print('tasks: ' + str(tasks))
    # 将前端推放进来的数据存放到任务队列中
    task_producer(tasks)
    return str(tasks)
demo.py
import threading
import time
from Queue import Queue as queue
from functools import wraps
import sys
import os
import fcntl

q = queue()

def task_monitor():
	# 监控队列中是否存在待执行任务,若存在则处理(打印),并从队列中取出。
    while True:
        L = []
        if q.qsize() != 0:
            L.append(q.get())
            q.task_done()
        for x in L:
            print('x: ' + str(x))
        time.sleep(5)

def task_consumer():
	# 设置守护线程
    thr = threading.Thread(target = task_monitor, args = (), kwargs = {})
    thr.setDaemon(True)
    thr.start()
    print(str(thr))
    return thr

def task_producer(tasks):
	# 向队列中存放任务
    for task in tasks:
        q.put(task)
执行结果

这里是简易版的,重启后台进程将导致队列中内容丢失。

# 请求任务1,2
$ curl 0.0.0.0:10800/demo?tasks=1\&tasks=2
# 后台处理任务1,2
tasks: [1, 2]
127.0.0.1 - - [03/Aug/2020 16:04:45] "GET /demo?tasks=1&tasks=2 HTTP/1.1" 200 -
x: 1
x: 2

# 请求任务1,2
# 在处理1的过程,flask后台重启
$ tasks: [1, 2]
127.0.0.1 - - [03/Aug/2020 16:05:53] "GET /demo?tasks=1&tasks=2 HTTP/1.1" 200 -
x: 1
 * Detected change in '/root/flask/myproject/stor/demo.py', reloading
 * Restarting with stat
/root/flask/myproject
<Thread(Thread-1, started daemon 140206898276096)>
 * Debugger is active!
 * Debugger PIN: 374-140-162

# 任务2丢失

添加缓存任务持久化逻辑

缓存队列持久化,主要是对共享队列在初始化与析构时,存储缓存队列中的内容。具体的,flask后台重启的逻辑会启动垃圾回收机制,将代码逻辑中的数据清空。若在队列清空时也就是被垃圾回收时能够将数据持久化到文件中,那么数据将被保留下来而避免了丢失。

缓存文件

具体实现中,将缓存队列Queue封装到类中。在初始化对象时,查看是否拥有为加载的文件,在析构时将缓存队列中的数据持久化的文件中。

import threading
import time
from Queue import Queue as queue
from functools import wraps
import sys
import os
import fcntl

class Cache:
    def __init__(self):
        self.q = queue()
        self.root_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
        self.cache_path = os.path.dirname(os.path.join(self.root_path, 'log/'))
        self.cache_name = os.path.join(self.cache_path, 'taskid.json')

    def Queue(self):
        return self.q

    def check(self):
        if(os.path.exists(self.cache_name)):
            with open(self.cache_name, 'r') as f:
                for task in f.readlines():
                    print('get task: ' + str(task))
                    self.q.put(task.strip())
        os.remove(self.cache_name)

    def __del__(self):
        with open(self.cache_name, 'a') as f:
            while(0 < self.q.qsize()):
                task = self.q.get()
                print('put task: ' + str(task))
                f.write(str(task) + '\n')
                self.q.task_done()

task = Cache()
q = task.Queue()

#q = queue()

def task_monitor():
    task.check()
    while True:
        L = []
        if q.qsize() != 0:
            L.append(q.get())
            q.task_done()
        for x in L:
            print('x: ' + str(x))
        time.sleep(5)

def task_consumer():
    thr = threading.Thread(target = task_monitor, args = (), kwargs = {})
    thr.setDaemon(True)
    thr.start()
    print(str(thr))
    return thr

def task_producer(tasks):
    for task in tasks:
        q.put(task)
执行任务
# 发起请求
$ curl 0.0.0.0:10800/demo?tasks=1\&tasks=2

# 执行结果
tasks: [1, 2]
127.0.0.1 - - [03/Aug/2020 16:42:00] "GET /demo?tasks=1&tasks=2 HTTP/1.1" 200 -
tasks: [3, 4]
127.0.0.1 - - [03/Aug/2020 16:42:05] "GET /demo?tasks=3&tasks=4 HTTP/1.1" 200 -
 * Detected change in '/root/flask/myproject/stor/demo.py', reloading
put task: 1
put task: 2
put task: 3
put task: 4
 * Restarting with stat
/root/flask/myproject
get task: 1

get task: 2

get task: 3

get task: 4

x: 1
# 重启后台进程
<Thread(Thread-1, started daemon 140067621132032)>
 * Debugger is active!
 * Debugger PIN: 374-140-162
 * Detected change in '/root/flask/myproject/stor/demo.py', reloading
put task: 2
put task: 3
put task: 4
 * Restarting with stat
/root/flask/myproject
get task: 2

get task: 3

get task: 4

x: 2
<Thread(Thread-1, started daemon 139786904717056)>
 * Debugger is active!
 * Debugger PIN: 374-140-162
 * Detected change in '/root/flask/myproject/stor/demo.py', reloading
put task: 3
put task: 4
 * Restarting with stat
/root/flask/myproject
get task: 3

get task: 4

x: 3
<Thread(Thread-1, started daemon 140183869146880)>
 * Debugger is active!
 * Debugger PIN: 374-140-162
 * Detected change in '/root/flask/myproject/stor/demo.py', reloading
put task: 4
 * Restarting with stat
/root/flask/myproject
get task: 4

x: 4
<Thread(Thread-1, started daemon 140620198328064)>
 * Debugger is active!

总结

仍旧有很多思路去解决这个问题,使用装饰器,使用进程。还待实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值