gpt4 book ai didi

python - 缓存 Flask-登录 user_loader

转载 作者:行者123 更新时间:2023-11-28 18:40:16 27 4
gpt4 key购买 nike

我有这个。

@login_manager.user_loader
def load_user(id=None):
return User.query.get(id)

在我引入 Flask-Principal 之前它一直运行良好。

@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):

# Set the identity user object
identity.user = current_user
# return
if hasattr(current_user, 'id'):
identity.provides.add(UserNeed(current_user.id))

# Assuming the User model has a list of roles, update the
# identity with the roles that the user provides
if hasattr(current_user, 'roles'):
for role in current_user.roles:
identity.provides.add(RoleNeed(role.name))

添加这个会导致严重的性能问题。 SQLALCHEMY_ECHO 显示每次加载静态文件时都会查询 User 表。

#Warning: Dummy Cache
users = {}
@login_manager.user_loader
def load_user(uid=None):
if uid not in users:
users[uid] = User.query.get(uid)
return users[uid]

在这个解决了重复查询问题的实验之后,我开始意识到我需要在我的 Flask 应用程序中引入缓存。这是问题。

  1. 如何缓存 User.query.get(id)
  2. 我什么时候需要清除此用户缓存?

最佳答案

老问题,但在 SO 上或通过谷歌似乎没有其他答案,我花了一些时间来解决这个问题,所以也许这个答案会对某人有所帮助。

首先,你需要一些缓存后端,我使用flask-cachingredis使用来自 pypi sudo pip install redis 的 python redis 库。

接下来,执行 from flask_caching import Cache,然后执行 cache = Cache(),这是我在另一个名为 extensions.py 的文件中执行的操作。如果您使用应用工厂模式,这一点很重要,因为稍后您需要导入 cache,这有助于避免较大的 Flask 应用出现循环引用问题。

在此之后,您需要在 flask 应用程序上注册 flask-caching 扩展,我做了一个单独的 app.py 文件,如下所示:

from flask import Flask
from extensions import cache

def create_app(config_obj=None):
"""An application factory"""

app = Flask(__name__)
app.config.from_object(config_obj)
cache.init_app(app, config={'CACHE_TYPE': 'redis',
'CACHE_REDIS_HOST': '127.0.0.1',
'CACHE_REDIS_PORT': '6379',
'CACHE_REDIS_URL': 'redis://127.0.0.1:6379'})
return app

现在 cache 已在 Flask 中注册,它可以从 extensions.py 导入并在整个应用程序中使用,而不会出现循环引用问题。移动到您正在使用 user_loader 的任何文件:

import pickle
from flask import current_user
from extensions import cache
from models.user_models import User

@login_manager.user_loader
def load_user(user_id):
"""Load user by ID from cache, if not in cache, then cache it."""
# make a unique cache key for each user
user = 'user_{}'.format(user_id)
# check if the user_object is cached
user_obj = pickle.loads(cache.get(user)) if cache.get(user) else None
if user_obj is None:
query = User.query.get(int(user_id))
user_obj = pickle.dumps(query)
cache.set(user, user_obj, timeout=3600)
return query
return user_obj

最后,当您注销用户时,您可以将它们从缓存中删除:

@blueprint.route('/logout/')
@login_required
def logout():
"""Logout."""
# remove the user information from redis cache
user = 'user_{}'.format(current_user.id)
cache.delete(user)
# remove the user information from the session
logout_user()
# Remove session keys set by Flask-Principal
for key in ('identity.name', 'identity.auth_type'):
session.pop(key, None)
flash('You are logged out.', 'info')
return redirect(url_for('public.home')

这似乎工作得很好,它减少了每个用户每页三个查询对 SQLAlchemy 的查询命中,并将我的应用程序的几个部分的页面加载速度提高了 200 毫秒,同时消除了达到 SQLAlchemy 连接池限制的讨厌问题。

此解决方案的最后一个重点。如果您出于任何原因更改用户对象,例如,如果为用户分配新角色或能力,则必须从缓存中清除用户对象。例如如下:

# set the user_id from current_user.id CACHE object
user_id = current_user.id
# remove the old USER object from cache since you will change it
# first set the cache key to user_{id}
cache_user = 'user_{}'.format(user_id)
# now delete the cache key
cache.delete(cache_user)

背景:

我需要考虑缓存 flask-login user_loader 是因为我通过扩展 flask-login 类 UserMixinAnonymousUserMixin 实现了访问控制列表管理一些类方法,如 get_rolesget_abilities。我也在使用 flask-sqlalchemy 和 postgresql 后端,并且有一个角色表和一个与用户对象有关系的能力表。这些用户角色和能力主要在模板中进行检查,以根据用户角色和能力呈现各种 View 。

在某些时候,我注意到当打开多个浏览器选项卡或只是浏览器在我的应用程序中重新加载页面时,我开始收到错误消息 TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30。 Flask-sqlalchemy 有 SQLALCHEMY_POOL_SIZESQLALCHEMY_MAX_OVERFLOW 的设置,但增加这些值只是掩盖了我的问题,错误仍然发生只是通过加载更多选项卡或重新加载更多页面。

深入挖掘以找出根本原因,我使用 SELECT * FROM pg_stat_activity; 查询了我的 postgresql 数据库,发现在每个请求中我都在累积多个连接,状态为 idle in transaction 其中 SQL 查询明确链接到用户、角色、能力访问检查。这些 idle in transaction 连接导致我的数据库连接池达到容量。

进一步测试发现,缓存 flask-login user_loader User 对象消除了 idle in transaction 连接,然后即使我离开了 SQLALCHEMY_POOL_SIZESQLALCHEMY_MAX_OVERFLOW 为默认值,我没有再遇到 TimeoutError: QueuePool limit。问题解决了!

关于python - 缓存 Flask-登录 user_loader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27078347/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com