我将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连接,并且永远不会关闭它。这是数据库状态的普罗米修斯图:
在芹菜开始时,连接似乎也大大增加,并且保持了一定的稳定性。 (下降是因为我已经重新启动了Postgres)。
我无法解释的另一件事是,为什么在调用after_return
时self_Session
始终为None,所以从未调用self._Session.remove()
。
[编辑]:
通过查看所有日志,我发现有时self._Session.remove()
不是None,所以self._Session.remove()
会被调用,但并不是每次after_return
都会被调用。