从辅助线程使用Flask SQLAlchemy [英] Using Flask SQLAlchemy from worker threads

查看:207
本文介绍了从辅助线程使用Flask SQLAlchemy的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 Flask RESTful 的python应用程序格式为烧瓶SQLAlchemy .我正在编写的API的一部分具有消灭 Timer的副作用. 对象. Timer到期时,它将执行一些数据库查询.我看到一个应该更新数据库中行(sqlite后端)的代码实际上没有发出任何UPDATE语句的问题.我已经通过打开SQLALCHEMY_ECHO标志来记录SQL语句来验证这一点.代码是否有效似乎是随机的.大约有一半的时间它未能发出UPDATE语句.参见下面的完整示例.

I have a python app that uses Flask RESTful as well as Flask SQLAlchemy. Part of the API I'm writing has the side effect of spinning off Timer objects. When a Timer expires, it executes some database queries. I'm seeing an issue in which code that is supposed to update rows in the database (a sqlite backend) is actually not issuing any UPDATE statements. I have verified this by turning the SQLALCHEMY_ECHO flag on to log the SQL statements. Whether or not the code works seems to be random. About half the time it fails to issue the UPDATE statement. See full example below.

我的猜测是,当从辅助线程调用SQLAlchemy Flask时,它无法正常工作.我认为Flask SQLAlchemy的重点之一是针对每个API请求为您管理SQLAlchemy会话.显然,由于Timer到期时没有任何API请求,因此我可以看到哪里可能无法正常工作.

My guess here is that SQLAlchemy Flask does not work properly when called from a worker thread. I think part of the point of Flask SQLAlchemy is to manage the SQLAlchemy sessions for you per API request. Obviously since there are no API requests going on when the Timer expires, I could see where things may not work properly.

为了测试这一点,我继续使用python的编写了一个简单的数据访问层sqlite3界面,似乎可以解决问题.

Just to test this, I went ahead and wrote a simple data access layer using python's sqlite3 interface and it seems to solve the problem.

我真的很想不必重写一堆数据访问代码.在这种情况下,有没有办法让Flask SQLAlchemy正常工作?

I'd really rather not have to rewrite a bunch of data access code though. Is there a way to get Flask SQLAlchemy to work properly in this case?

在这里设置烧瓶应用程序并保存SQLAlchemy db对象:

Here's where I set up the flask app and save off the SQLAlchemy db object:

from flask import Flask
from flask_restful import Api
from flask.ext.sqlalchemy import SQLAlchemy
from flask_cors import CORS
import db_conn

flask_app = Flask(__name__)
flask_app.config.from_object('config')
CORS(flask_app)
api = Api(flask_app)
db_conn.db = SQLAlchemy(flask_app)

api.add_resource(SomeClass, '/abc/<some_id>/def')

这是我创建ORM模型的方式:

Here's how I create the ORM models:

import db_conn

db = db_conn.db

class MyTable(db.Model):
    __tablename__ = 'my_table'
    id = db.Column(db.Integer, primary_key=True)
    phase = db.Column(db.Integer, nullable=False, default=0)

    def set_phase(self, phase):
        self.phase = phase
        db.session.commit()

这是带有计时器和数据库调用失败的API处理程序:

Here's the API handler with timer and the database call that is failing:

from flask_restful import Resource
from threading import Timer
from models import MyTable
import db_conn
import global_store

class SomeClass(Resource):    
    def put(self, some_id):
        global_store.saved_id = some_id
        self.timer = Timer(60, self.callback)
        return '', 204

    def callback(self):
        row = MyTable.query.filter_by(id=global_store.saved_id).one()

        # sometimes this works, sometimes it doesn't
        row.set_phase(1)
        db_conn.db.session.commit()

推荐答案

我猜在您的回调中,您实际上并没有更改对象的值.如果会话状态不脏,SQLAlchemey将不会发出DB UPDATE调用.因此,如果由于某种原因该阶段已经为1,则无需执行任何操作.

I'm guessing in your callback you aren't actually changing the value of the object. SQLAlchemey won't issue DB UPDATE calls if the session state is not dirty. So if the phase is already 1 for some reason there is nothing to do.

这篇关于从辅助线程使用Flask SQLAlchemy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆