在其他地方看到了这样一种处理方式
@self.app.before_request
def init_session():
g.session = self.session_factory()
@self.app.after_request
def close_session(response):
g.session.close()
return response
这里的session_factory()
是
self.session_factory = scoped_session(sessionmaker(self.engine))
这样做的目的是在同一个线程能保证有唯一session,一方面是线程安全,一方面是避免出现重复申请session导致连接池满的问题。同时通过g访问session看起来方便。
初期实现确实很爽,但是跑了一阵就遇到了很多问题。最常见的就是session异常没有rollback导致请求失败。这个错误随机性很高,不好排查。
我因为这个问题质疑了好一阵Flask的实际能力,今天突然想通了,就是那个实现方式的锅。
下面是我的推测,没有经过实际验证
flask本身是单线程的,通过wsgi服务器可以搞成多进程运行提高性能。那么相当于在一个线程里面,所有逻辑都共用了一个session。如果只是单纯的接口,因为after_requests里面关闭了session,只要注意提交的时候捕获一下异常即可。
然而如果你的应用中在其他地方也在使用这个session,就很可能出问题了。
一些思路
如果你是纯Flask应用,不涉及任何视图函数之外的数据库逻辑,请直接使用flask-sqlalchemy。它封装的session默认是scoped_session。
如果还有很多外部代码,一定保证你的session是可控的。
简单来说就是:
- 用就开,用完就关
- 尽量避免多个函数依赖之间同时使用session
- 使用scoped_session来保证线程安全
网友评论