将SQLAlchemy scoped_session与Celery结合使用

时间:2018-10-04 08:55:10

标签: python sqlalchemy celery

我将SQLAlchemy与Celery 用作后端(我正在使用的Celery后端是RabbitMQ)。

阅读此question和SQLAlchemy文档,我想出了以下解决方案:

首先,我实现了一个扩展Celery的Task类的类:

class DBTask(Task):
    _engine = None
    _Session = None

    def __init__(self):
        self.logger = get_task_logger('__name__')

    def after_return(self, *args, **kwargs):
        self.logger.info("DBTask: Removing session. {}".format(self._Session))
        if self._Session is not None:
            self.logger.debug("DBTask: Session removed. {}".format(self._Session))
            self._Session.remove()

    @property
    def engine(self):
        if self._engine is None:
            self.logger.info("DBTask: Creating engine.")
            self.config = GlobalConfigReader().get_config()
            self._engine = create_engine(self.config['postgres_uri'], pool_pre_ping=True)
        return self._engine

    @property
    def Session(self):
        if self._Session is None:
            self._Session = scoped_session(sessionmaker(bind=self.engine))
            self.logger.info("DBTask: Creating new session: {}".format(self._Session))
            Base.metadata.create_all(self.engine)
        return self._Session

在我的一项任务中,我执行以下操作:

self process(self, message):
        try:
            session = self.Session()

            db_alert = self._find_existing_alert(session, message['event'], 
            session.commit()
        except:
            self.logger.debug("Rolling back session. {}".format(session))
            session.rollback()
            raise
        # further processing
        context.delay(message)

似乎在线程中运行的每个Celery Task都会创建一个新的DB连接,并且永远不会关闭它。这是数据库状态的普罗米修斯图:

prometheus graph

在芹菜开始时,连接似乎也大大增加,并且保持了一定的稳定性。 (下降是因为我已经重新启动了Postgres)。

我无法解释的另一件事是,为什么在调用after_returnself_Session始终为None,所以从未调用self._Session.remove()

[编辑]: 通过查看所有日志,我发现有时self._Session.remove()不是None,所以self._Session.remove()会被调用,但并不是每次after_return都会被调用。

0 个答案:

没有答案