다음을 위한 앱을 만들고 있습니다.
웹 페이지 요청 처리(db 읽기/쓰기)
websockets 클라이언트가 다른 시스템과 통신하기 때문에(db 읽기/쓰기);
Python Flask 프레임워크를 사용하고 있습니다.
웹 페이지를 제공하고 템플릿을 렌더링하는 간단한 앱이 있으면 모두 괜찮습니다. 구현된 SQLAlchemy 단순 데이터베이스 - 웹 페이지에서 잘 작동합니다.
일부 정보를 쿼리하고 해당 정보를 내 로컬 데이터베이스에 저장하기 위해 일부 외부 시스템과 통신하기 위해 웹 소켓 클라이언트를 구현했습니다.
이 웹 소켓 클라이언트는 외부 시스템과 비동기식으로 통신하기 위해 별도의 스레드로 구현했습니다. 이 스레드는 정상적으로 작동합니다.
문제는 데이터베이스 액세스 및 사용에 있습니다. websockets 클라이언트 스레드에서 데이터베이스를 사용하려고 할 때 "RuntimeError: Working outside of application context" 오류가 발생합니다. 또는 "RuntimeError: 응용 프로그램을 찾을 수 없습니다. 보기 기능 내에서 작업하거나 응용 프로그램 컨텍스트를 푸시하십시오."
아래 내 코드를 참조하십시오(단순화). 나는 app_context로 플레이하려고 했지만 올바른 방법을 찾지 못했습니다.
동일한 앱의 외부 시스템에 대한 Flask 웹 앱 및 Websockets 클라이언트의 접근 방식이 나쁜 생각일까요? 다른 접근 방식을 선택해야 합니까?
대부분의 Flask 앱 및 Websockets 샘플은 웹 페이지와 웹 소켓이 함께 작동하는 방식으로 빌드됩니다. 그러나 내 상황에서는 외부 시스템과 통신하고 수신된 데이터를 다른 쪽 끝에서 웹 페이지 렌더링에 사용되는 동일한 데이터베이스에 저장하기 위해 websockets 클라이언트가 필요합니다.
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()
Flask 앱 코드 생성:
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
데이터베이스 초기화 코드:
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()
여기서 문제는 동일한 데이터베이스에 다른 스레드에서 액세스하는 방법입니다. 그리고 이 문제에 대한 해결책은 이 별도의 스레드를 위한 전용 db 세션을 만드는 것입니다.
다음과 같습니다.
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()
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다