【问题标题】:how to setup sqlalchemy session in celery tasks with no global variable如何在没有全局变量的芹菜任务中设置 sqlalchemy 会话
【发布时间】:2015-11-07 01:44:40
【问题描述】:

总结:我想在 celery 任务中使用 sqlalchemy 会话,而不需要包含该会话的全局变量。

我在一个带有 celery 任务的项目中使用 SQLAlchemy,我正在使用

目前,我在 celery 应用程序设置 (celery.py) 中定义了一个全局变量“会话”,并带有一个工作信号来设置它。

session = scoped_session(sessionmaker())

@celeryd_init.connect
def configure_workers(sender=None, conf=None, **kwargs):
    # load the application configuration
    # db_uri = conf['db_uri']
    engine = create_engine(db_uri)
    session.configure(bind=engine)

在定义任务的模块中,我只需导入“会话”并使用它。任务是使用自定义类定义的,该类在返回后关闭会话:

class DBTask(Task):
    def after_return(self, *args, **kwargs):
        session.remove()

但效果很好:当使用 CELERY_ALWAYS_EAGER=True 进行单元测试时,不会配置会话。到目前为止,我发现的唯一解决方案是在单元测试中运行任务时模拟“会话”变量:

with mock.patch('celerymodule.tasks.session', self.session):
    do_something.delay(...)

虽然它有效,但我不想这样做。

有什么方法可以设置一个不是全局变量的会话,它既适用于正常的异步行为,也适用于没有 CELERY_ALWAYS_EAGER=True 的工作人员?

【问题讨论】:

    标签: python sqlalchemy celery


    【解决方案1】:

    关于custom task classes的官方文档中的答案就在我的眼皮底下。

    我修改了用于访问数据库的任务的自定义任务类:

    class DBTask(Task):
        _session = None
    
        def after_return(self, *args, **kwargs):
            if self._session is not None:
                self._session.remove()
    
        @property
        def session(self):
            if self._session is None:
                _, self._session = _get_engine_session(self.conf['db_uri'],
                                                       verbose=False)
    
            return self._session
    

    我这样定义我的任务:

    @app.task(base=DBTask, bind=True)
    def do_stuff_with_db(self, conf, some_arg):
        self.conf = conf
        thing = self.session.query(Thing).filter_by(arg=some_arg).first()
    

    这样,SQLAlchemy 会话只会为每个 celery 工作进程创建一次,我不需要任何全局变量。

    这解决了我的单元测试问题,因为 SQLAlchemy 会话设置现在独立于 celery 工人。

    【讨论】:

    • 对于其他查看此内容并考虑将其用于数据库连接的人,而不仅仅是会话,请注意您不想要 after_return(),因为在每个任务结束时都会调用... d 只想拆除会话,而不是完整连接。
    • self.conf 没有在DBTask 基类上声明,这不是问题吗?
    • do_stuff_with_db 第一个参数是 self - 它是任何类的一部分吗?
    • @AmitTalmor celery bind=True 参数将self 作为第一个参数传递为任务的实例。 self.conf 继承自 Task,所以已经在那里定义了
    猜你喜欢
    • 2013-05-23
    • 1970-01-01
    • 2012-11-16
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 2021-04-25
    • 1970-01-01
    相关资源
    最近更新 更多