Sco*_*ott 2 python session multithreading sqlalchemy gunicorn
我有一个 Flask REST API,与 Gunicorn/nginx 堆栈一起运行。为 API 运行的每个线程设置一次全局 SQLAlchemy 会话。我设置了一个端点 /test/ 来运行 API 的单元测试。一项测试发出 POST 请求以将某些内容添加到数据库中,然后使用 finally: 子句进行清理:
def test_something():
try:
url = "http://myposturl"
data = {"content" : "test post"}
headers = {'content-type': 'application/json'}
result = requests.post(url, json=data, headers=headers).json()
validate(result, myschema)
finally:
db.sqlsession.query(MyTable).filter(MyTable.content == "test post").delete()
db.sqlsession.commit()
Run Code Online (Sandbox Code Playgroud)
问题是,发出 POST 请求的线程现在在其会话中有一个“test post”对象,但数据库没有这样的对象,因为运行测试的线程从数据库中删除了该对象。因此,当我向服务器发出 GET 请求时,大约有四分之一的时间(我有 4 个 Gunicorn 工作人员)得到“测试帖子”对象,而四分之三的时间没有得到。这是因为每个线程都有自己的会话对象,并且它们不同步,但我真的不知道该怎么办......
这是我的 SQLAlchemy 会话的设置:
def connectSQLAlchemy():
import sqlalchemy
import sqlalchemy.orm
engine = sqlalchemy.create_engine(connection_string(DBConfig.USER, DBConfig.PASSWORD, DBConfig.HOST, DBConfig.DB))
session_factory = sqlalchemy.orm.sessionmaker(bind=engine)
Session = sqlalchemy.orm.scoped_session(session_factory)
return Session()
# Create a global session for everyone
sqlsession = connectSQLAlchemy()
Run Code Online (Sandbox Code Playgroud)
如果您使用flask,请使用flask-sqlalchemy,它会为您处理会话的生命周期。
如果您坚持自己做,正确的模式是为每个请求创建一个会话,而不是创建一个全局会话。你应该做
Session = scoped_session(session_factory, scopefunc=flask._app_ctx_stack.__ident_func__)
return Session
Run Code Online (Sandbox Code Playgroud)
代替
Session = scoped_session(session_factory)
return Session()
Run Code Online (Sandbox Code Playgroud)
并做
session = Session()
Run Code Online (Sandbox Code Playgroud)
每次您需要会话时。凭借 和scoped_session,scopefunc这将在每个请求中返回不同的会话,但在同一请求中返回相同的会话。
| 归档时间: |
|
| 查看次数: |
3236 次 |
| 最近记录: |