Multithreading flask sqlalchemy-如何获得独立于请求的db会话

Multithreading flask sqlalchemy-如何获得独立于请求的db会话,multithreading,flask,sqlalchemy,python-multithreading,Multithreading,Flask,Sqlalchemy,Python Multithreading,我正在寻找获得独立于请求的db会话的最佳(也是正确的)方法 问题如下:我正在构建一个必须访问数据库的web应用程序。暴露的端点接受一个请求,执行第一个工作,然后创建一个线程(将执行艰难的工作),启动它,并使用“作业”的唯一id回复客户机。同时,线程继续工作(必须访问数据库),客户端可以执行轮询以检查状态。我并没有使用专门的框架来执行这个后台工作,而只是一个简单的线程。我在任何时候都只能有一个后台线程在运行,因为这个原因,我在单例中维护状态 应用程序是使用应用程序工厂设计创建的 我使用Gunico

我正在寻找获得独立于请求的db会话的最佳(也是正确的)方法

问题如下:我正在构建一个必须访问数据库的web应用程序。暴露的端点接受一个请求,执行第一个工作,然后创建一个线程(将执行艰难的工作),启动它,并使用“作业”的唯一id回复客户机。同时,线程继续工作(必须访问数据库),客户端可以执行轮询以检查状态。我并没有使用专门的框架来执行这个后台工作,而只是一个简单的线程。我在任何时候都只能有一个后台线程在运行,因为这个原因,我在单例中维护状态

应用程序是使用应用程序工厂设计创建的

我使用Gunicorn作为WSGI服务器,使用sqlite作为数据库

代码的基本结构如下(我正在删除业务逻辑和导入,但概念仍然存在):

api_jobs.py


@bp.route('/jobs',methods=['POST'])
def create_job():
data=request.get_json(force=True)或{}
名称=数据['name']
job_controller=JobController()#这是一个单例
作业流程=作业控制器。启动作业(名称)
job\u process\u dict=job\u process.to\u dict()
返回jsonify(作业、流程、指令)
controller.py


类单例(类型):
_实例={}
定义调用(cls、*ARG、**kwargs):
如果cls不在cls.\u实例中:
cls._实例[cls]=super(单例,cls)。_调用(*args,**kwargs)
返回cls.\u实例[cls]
类JobController(对象):
__元类\单例
定义初始化(自):
self.job\u线程=无
def start_作业(自身,名称):
如果self.job_线程不是None:
job\u id=self.job\u线程.job\u id
job\u process=JobProcess.query.get(作业id)
如果作业\u进程状态!='"完":
raise VALUERROR('作业进程已在进行!')
其他:
self.job\u线程=无
作业流程=作业流程(名称)
db.session.add(作业处理)
db.session.commit()
self.job\u thread=JobThread(db.session,job\u process.id)
self.job_thread.start()
返回作业流程
类JobThread(threading.Thread):
定义初始化(自我、数据库会话、作业id):
self.job\u id=job\u id
self.db\u session=db\u session
self.session=self.db_session()
def运行(自):
self.job\u process=self.session.query(JobProcess).get(self.job\u id)
self.job\u process.status='working'
self.session.commit()
i=0
尽管如此:
睡眠(1)
打印(‘努力工作’)
i=i+1
如果i>10:
打破
self.job\u process.status='end'
self.session.commit()
self.db_session.remove()
models.py

类作业流程(db.Model):
id=db.Column(db.Integer,主键=True)
status=db.Column(db.String(64))
name=db.Column(db.String(64))
def到dict(自身):
数据={
“id”:self.id,
“状态”:自我状态,
“name”:self.name,
}
返回数据
根据我的理解,调用
self.session=self.db_session()
实际上什么都不做(因为sqlalchemy使用的是一个注册表,如果我没有错的话,它也是一个代理),但是这是我发现创建“新的/分离的/有用的”会话的最佳尝试

我签出是为了获得独立于请求的db会话,但是即使使用建议的创建新会话工厂的方法(sessionmaker+scoped_session)也不起作用

我得到的错误是多个的,在这个配置中,错误是

DetachedInstanceError: Instance <JobProcess at 0x7f875f81c350> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)
DetachedInstanceError:实例未绑定到会话;属性刷新操作无法继续(此错误的背景信息位于:http://sqlalche.me/e/bhk3)

基本问题仍然存在:是否有可能创建一个将在线程内运行的会话,并且我将负责创建/删除该会话?

遇到DetachedInstanceError的原因是您试图将会话从主线程传递到作业线程。Sqlalchemy使用线程本地存储来管理会话,因此单个会话不能在两个线程之间共享。您只需要在作业线程的run方法中创建一个新会话