在SQLAlchemy中正确使用与异步服务器的会话

时间:2012-11-22 11:21:23

标签: asynchronous sqlalchemy gunicorn eventlet

背景:

我们有一个Python Web应用程序,它使用SqlAlchemy作为ORM。我们目前使用Gunicorn(同步工作者)运行此应用程序。此应用程序仅用于响应 LONG RUNNING REQUESTS (即提供大文件,请不要建议使用X-Sendfile / X-Accel-Redirect,因为响应是从Python应用程序动态生成的。)< / p>

对于Gunicorn同步工作者,当我们运行8名工作人员时,只有8名请求同时提供。由于所有这些响应都是IO绑定的,我们希望切换到异步工作者类型以获得更好的吞吐量。

我们已在Gunicorn配置文件中将工作类型从同步切换到eventlet。现在我们可以同时回应所有请求,但又出现了另一个神秘的(对我来说很神秘)问题。

在应用程序中,我们在模块级别有一个范围的会话对象。以下代码来自我们的orm.py文件:

uri = 'mysql://%s:%s@%s/%s?charset=utf8&use_unicode=1' % (\
    config.MYSQL_USER,
    config.MYSQL_PASSWD,
    config.MYSQL_HOST,
    config.MYSQL_DB,
)

engine = create_engine(uri, echo=False)

session = scoped_session(sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine,
    query_cls=CustomQuery,
    expire_on_commit=False    
))

我们的应用程序使用如下会话:

from putio.models import session

f = session.query(File).first()
f.name = 'asdf'
session.add(f)
session.commit()

虽然我们使用同步工作程序,但是一次只使用1个请求。在我们切换到异步eventlet worker之后,同一个worker中的所有请求共享同一个不需要的会话。当会话在一个请求中提交或发生异常时,所有其他请求都会因为会话被共享而失败。

在SQLAlchemy的文档中,表示scoped_session用于线程环境中的分离会话。异步工作程序中的AFAIK请求在同一个线程中运行。

问题:

我们希望异步工作程序中的每个请求都有单独的会话。在SQLAlchemy中使用与异步工作程序的会话的正确方法是什么?

1 个答案:

答案 0 :(得分:1)