How to use Flask-SQLAlchemy in a Celery task

前端 未结 4 1614
傲寒
傲寒 2020-12-12 09:55

I recently switch to Celery 3.0. Before that I was using Flask-Celery in order to integrate Celery with Flask. Although it had many issues like hiding some powerful Celery f

4条回答
  •  北荒
    北荒 (楼主)
    2020-12-12 10:55

    from flask import Flask
    from werkzeug.utils import import_string
    from celery.signals import worker_process_init, celeryd_init
    from flask_celery import Celery
    from src.app import config_from_env, create_app
    
    celery = Celery()
    
    def get_celery_conf():
        config = import_string('src.settings')
        config = {k: getattr(config, k) for k in dir(config) if k.isupper()}
        config['BROKER_URL'] = config['CELERY_BROKER_URL']
        return config
    
    @celeryd_init.connect
    def init_celeryd(conf=None, **kwargs):
        conf.update(get_celery_conf())
    
    @worker_process_init.connect
    def init_celery_flask_app(**kwargs):
        app = create_app()
        app.app_context().push()
    
    • Update celery config at celeryd init
    • Use your flask app factory to inititalize all flask extensions, including SQLAlchemy extension.

    By doing this, we are able to maintain database connection per-worker.

    If you want to run your task under flask context, you can subclass Task.__call__:

    class SmartTask(Task):
    
        abstract = True
    
        def __call__(self, *_args, **_kwargs):
            with self.app.flask_app.app_context():
                with self.app.flask_app.test_request_context():
                    result = super(SmartTask, self).__call__(*_args, **_kwargs)
                return result
    
    class SmartCelery(Celery):
    
        def init_app(self, app):
            super(SmartCelery, self).init_app(app)
            self.Task = SmartTask
    

提交回复
热议问题