Reputation: 47
I am building an app for:
handle web page requests (read/write db);
as websockets client do communication with some other system (read/write db);
I am using Python Flask framework.
Have some simple app serving web pages, rendering templates - all is ok. Implemented SQLAlchemy simple database - it is working for web page serving very well.
Implemented websockets client to communicate with some external system to query some information and want to store that information into my local database.
This websockets client I implemented as separate thread to asynchronously communicate with external system. This thread is working ok.
Problem is with accessing and using database - when I try to use database from websockets client thread I'm getting error "RuntimeError: Working outside of application context." or "RuntimeError: No application found. Either work inside a view function or push an application context."
See my code below (simplified). I was trying to play with app_context but have not found the right way.
Maybe my approach with Flask web app and Websockets client to external system in the same app is bad idea? Should I choose different approach?
Most of the Flask app and Websockets samples are built in a way for web page and websocket to work together. But in my situation I need websockets client to communicate with external system and store received data into same database which is used for web page rendering on the other end.
class MyDataModel(db.Model):
title = db.Column(db.String(80), unique=True, nullable=False, primary_key=True)
def __repr__(self):
return "<Title: {}>".format(self.title)
class WSClientThread(Thread):
def on_message(ws, message):
from flask import current_app
# -----> PROBLEM HERE !!!
with current_app.app_context():
db.session.add(MyDataModel(title='AAA222'))
db.session.commit()
# <------ PROBLEM !!!
def __init__(self):
self.wsa = websocket.WebSocketApp('ws://IP:PORT', on_message=self.on_message)
super(WSClientThread, self).__init__()
def send(self, msg):
self.wsa.send(msg)
def run(self):
self.wsa.run_forever()
Create Flask app code:
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
with app.app_context():
db.init_app(app)
wsc = WSClientThread()
wsc.start()
app.add_url_rule("/", endpoint="index")
return app
Database initialization code:
db = SQLAlchemy()
def init_app(app):
app.cli.add_command(init_db_command)
db.init_app(app)
@click.command("init-db")
@with_appcontext
def init_db_command():
init_db()
def init_db():
db.drop_all()
db.create_all()
# test data insert - works OK
db.session.add(MyDataModel(title='AAA'))
db.session.commit()
Upvotes: 1
Views: 390
Reputation: 47
The problems here is how to access the same database but from different thread. And solution to this problem is to create dedicated db session for this separate thread.
It is like this:
db_engine = create_engine(dburl, echo=False)
DBSession = scoped_session(
sessionmaker(
autoflush=True,
autocommit=False,
bind=db_engine))
DBSession.add(MyDataModel(title='AAA'))
DBSession.commit()
Upvotes: 1