Flask RQ任务报Working outside of application上下文错误如何解决
问题根因
RQ worker为独立运行的进程,与Flask主应用进程的内存空间完全隔离,主应用中推入的应用上下文无法被worker继承。你两个装饰器的报错都是上下文激活的时机错误导致的:
- 使用
redis_decorator1时,任务在worker中执行时没有激活的Flask应用上下文,调用current_app直接抛出上下文缺失错误 - 使用
redis_decorator2时,app.app_context().push()写在了装饰器的外层逻辑,应用启动加载模块、执行装饰器绑定的阶段就会触发上下文推入,此时要么app未完成初始化,要么上下文只存在于主进程,worker执行时依旧没有可用上下文
解决方案
方案1:调整装饰器逻辑,执行任务时动态激活上下文
推荐使用Flask工厂模式初始化应用,在任务实际执行的内层逻辑中推入上下文,适配worker的独立运行环境:
# 你的Flask应用工厂函数,可独立完成应用初始化 from your_app import create_app def redis_decorator(f): def inner_wrapper(*args, **kwargs): # worker执行任务时才初始化应用、激活上下文 app = create_app() with app.app_context(): # 所有DB操作、current_app调用都在上下文管理器内执行 return f(*args, **kwargs) return inner_wrapper # 装饰业务函数 @redis_decorator def under_decorator_func(*some_args): # 此处可正常使用current_app、Flask-SQLAlchemy等依赖上下文的对象 pass
方案2:Worker启动时全局初始化上下文
如果需要批量处理所有RQ任务的上下文问题,可以自定义worker启动脚本,启动worker时就完成应用初始化和上下文推入,无需单独给每个任务加装饰器:
# rq_worker_starter.py import redis from rq import Worker, Queue, Connection from your_app import create_app # worker进程启动时先初始化应用、推入全局上下文 app = create_app() app.app_context().push() listen_queues = ["default"] redis_conn = redis.Redis(host="127.0.0.1", port=6379) if __name__ == "__main__": with Connection(redis_conn): worker = Worker(map(Queue, listen_queues)) worker.work()
启动worker时不要使用默认的rq worker命令,改为执行上述脚本即可:python rq_worker_starter.py
内容的提问来源于stack exchange,提问作者Antonio Margaretti
相关产品推荐
相关产品推荐

