烧瓶会话(文件系统)取消酸洗会话对象错误,是否有大小限制或我是否损坏?



Python2.7/Centos7.5/Apache2.4.6 + mod_wsgi

我正在使用 flask/jinja 生成一些交互式 html 表单,并在更改之间将数据保存到会话文件中(flask_session/type=文件系统)。它在 werkzeug 的贡献/缓存的_prune函数期间随机中断了 Unpickling 错误.py我不知道为什么。删除会话文件将解决问题,直到它再次出现。从那以后,我已经能够通过强制会话文件的大小增长(使表单更长)来重现错误,所以我怀疑大小是相关的,但它并不能完全解释为什么它们首先发生。我遇到的服务器端会话文件/泡菜是否有一些大小限制?这不是完全可以预测的,我只知道当我开始超载事情时,它最终会发生。AFAIK 除了 jinja 渲染的 html 之外,没有任何东西被发送到客户端。

我加载了一个体面大小的 OrderedDict 作为会话项目:

session['saved'] = OrderedDict(items_list)

字典的深度只有3个级别,总共~300个键,当它有崩溃的风险。

我尝试更改会话项目阈值、更改会话文件的持久性、更新 werkzeug,并且我有一个解决方法,即在 UnpicklingError 上强制删除会话文件(这似乎根本不影响客户端体验)。但这是对werkzeug lib文件的手动编辑,绝对不是一个长期的解决方案。

Traceback (most recent call last):
File "/usr/lib64/python2.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/usr/lib64/python2.7/site-packages/flask/app.py", line 1816, in full_dispatch_request
return self.finalize_request(rv)
File "/usr/lib64/python2.7/site-packages/flask/app.py", line 1833, in finalize_request
response = self.process_response(response)
File "/usr/lib64/python2.7/site-packages/flask/app.py", line 2114, in process_response
self.session_interface.save_session(self, ctx.session, response)
File "/usr/lib64/python2.7/site-packages/flask_session/sessions.py", line 355, in save_session
total_seconds(app.permanent_session_lifetime))
File "/usr/lib/python2.7/site-packages/werkzeug/contrib/cache.py", line 815, in set
self._prune()
File "/usr/lib/python2.7/site-packages/werkzeug/contrib/cache.py", line 764, in _prune
expires = pickle.load(f)
UnpicklingError: invalid load key, '*'.

相关的 python 代码(为了可读性而进行了修剪和修改):

from flask import Flask, session, request, render_template
from flask_session import Session
from collections import OrderedDict
app = Flask(__name__)
SESSION_TYPE = app.config['SESSION_TYPE'] = 'filesystem'
SESSION_FILE_DIR = app.config['SESSION_FILE_DIR'] = os.path.join(local_dir,'flask_session')
SESSION_FILE_THRESHOLD = app.config['SESSION_FILE_THRESHOLD'] = 100
Session.init_app(app)
@app.route('/', defaults={'path': ''}, methods=['POST','GET'])
@app.route('/<path:path>', methods=['POST','GET'])
def configuration(path):
#Do Some Stuff
session['saved'] = OrderedDict(items_list)
return render_template('configuration.html', session=session)

相关金家

% for element, details in session.saved.items()
<tr id="{{element}}" name="{{details['type']}}">
<td>
<select id="{{element}}" name="{{element}}">
% for item, desc in details["items"]
<option value="{{item}}">{{desc}}</option>
% endfor
</select>
</td>
</tr>

_prune来自werkzeug/contrib/cache的功能.py为方便起见

def _prune(self):
if self._threshold == 0 or not self._file_count > self._threshold:
return
entries = self._list_dir()
now = time()
for idx, fname in enumerate(entries):
try:
remove = False
with open(fname, "rb") as f:
expires = pickle.load(f)
remove = (expires != 0 and expires <= now) or idx % 3 == 0
if remove:
os.remove(fname)
except (IOError, OSError):
pass
# Add Exception to delete file with pickle errors
except pickle.UnpicklingError:
os.remove(fname)
self._update_count(value=len(self._list_dir()))

我认为它不相关,考虑到它应该都是服务器端的,但是在使用烧瓶开发服务器的 Windows 环境中运行相同的脚本不会出现酸洗错误。相反,我在 self.flush() 中收到套接字错误 - 主机中的软件中止了已建立的连接。也没有崩溃,它只是继续。我怀疑这只是错误处理,但认为值得一提。

事实证明,在 flask_session 目录中还有另一个文件,werkzeug/contrib/cache 正在尝试加载并检查它是否需要修剪:

.gitignore

*脸掌*

这里的答案是不,它没有大小限制,不,没有损坏。 库试图纯粹基于目录内容修剪文件。

这是文件系统的行为,它会减慢应用程序的速度,最好使用 Redis 或某种缓存数据库系统。

app.config['SESSION_TYPE'] = 'redis'

最新更新