Using Flask SQLAlchemy from worker threads

▼魔方 西西 提交于 2019-12-11 06:17:02

问题


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.

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.

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.

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?

Sample code

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')

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()

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()

回答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.



来源:https://stackoverflow.com/questions/41580029/using-flask-sqlalchemy-from-worker-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!