From cef0a18bdd6ba1c70bce96d2ff07c58fb59d978b Mon Sep 17 00:00:00 2001 From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com> Date: Thu, 27 Mar 2025 23:51:42 -0400 Subject: [PATCH 1/2] server emits messages to the same socket id in prod --- .gitignore | 2 +- quantum_app_backend/app.py | 68 ++++++++++++++-------------- quantum_app_backend/requirements.txt | 3 +- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index a9f75ff..d2bb6fc 100644 --- a/.gitignore +++ b/.gitignore @@ -234,7 +234,7 @@ cover/ *.pot # Django stuff: -*.log +*.log* local_settings.py db.sqlite3 db.sqlite3-journal diff --git a/quantum_app_backend/app.py b/quantum_app_backend/app.py index 5a89f5d..9ab9edb 100755 --- a/quantum_app_backend/app.py +++ b/quantum_app_backend/app.py @@ -1,14 +1,14 @@ -import flask -from flask import Flask, jsonify +from gevent import monkey +monkey.patch_all() + +from flask import Flask, jsonify, request from flask_restx import Api from flask_cors import CORS from model_generators.tunneling import Wave_Packet3D as t_wp, Animator3D as t_ani from model_generators.interference import Wave_Packet3D as i_wp, Animator3D as i_ani from model_generators.Qgate1 import Qgate1 from model_generators.QuantumFourierTransform import QFTStepByStepODE -from model_generators.bloch import Bloch import matplotlib.pyplot as plt -import time import logging from logging.handlers import RotatingFileHandler import os @@ -16,6 +16,16 @@ from flask_socketio import SocketIO, emit from functools import wraps +sid = None + +#set swagger info +api: Api = Api( + title='quantum_modeling', + version='1.0', + description='v1.0', + prefix='/v1' +) + # Set up logging log_dir = 'logs' if not os.path.exists(log_dir): @@ -31,7 +41,7 @@ backupCount=5 ) file_handler.setFormatter(formatter) -file_handler.setLevel(logging.INFO) +file_handler.setLevel(logging.DEBUG) console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) @@ -42,22 +52,19 @@ logger.addHandler(console_handler) logger.setLevel(logging.DEBUG) -# Add this after the logger setup class SocketHandler(logging.Handler): - def __init__(self, socketio): + def __init__(self): super().__init__() - self.socketio = socketio - # No need for formatter since we're only using the message def emit(self, record): try: # Only emit INFO level and above to avoid flooding the client if record.levelno >= logging.INFO: - self.socketio.emit('status_update', {'message': record.getMessage()}) - except Exception: - self.handleError(record) + global sid + emit('status_update', {'message': record.getMessage()}, room=sid, namespace='/') + except Exception as e: + logger.error(f"Socket emission failed: {str(e)}", exc_info=True) -# Error handling decorator def handle_errors(f): @wraps(f) def wrapped(*args, **kwargs): @@ -69,19 +76,11 @@ def wrapped(*args, **kwargs): return jsonify({"error": str(e)}), 500 return wrapped -#set swagger info -api: Api = Api( - title='quantum_modeling', - version='1.0', - description='v1.0', - prefix='/v1' -) - app = Flask(__name__) api.init_app(app) CORS(app, resources={r"/*": {"origins": "*"}}) -socketio = SocketIO(app, cors_allowed_origins="*") -socket_handler = SocketHandler(socketio) +socketio = SocketIO(app, async_mode='gevent', cors_allowed_origins="*", logger=True, engineio_logger=True) +socket_handler = SocketHandler() socket_handler.setLevel(logging.INFO) logger.addHandler(socket_handler) mongo = MongoConnector() @@ -108,21 +107,18 @@ def Qtunneling(barrier, width, momentum): try: tunneling_model = mongo.get(t_collection, parameters) if not tunneling_model: - emit_status('Generating tunneling model...') plt.close('all') plt.switch_backend('Agg') - emit_status('Calculating tunneling model...') animator = t_ani(t_wp(barrier_height=barrier, barrier_width=width, k0=momentum)) - emit_status('Animating tunneling model...') tunneling_model = animator.animate3D() - # Upload to MongoDB asynchronously after returning response + # Upload to MongoDB asynchronously after emitting response + emit_status(f"Generated new tunneling model with parameters: {parameters}") socketio.start_background_task(mongo.upload, t_collection, parameters, tunneling_model) - logger.info(f"Generated new tunneling model with parameters: {parameters}") else: - logger.info(f"Retrieved existing tunneling model with parameters: {parameters}") + emit_status(f"Retrieved existing tunneling model with parameters: {parameters}") return tunneling_model except Exception as e: logger.error(f"Error generating tunneling model: {str(e)}", exc_info=True) @@ -154,9 +150,9 @@ def Qinterference(spacing, slit_separation, momentum): interference_model = animator.animate3D() socketio.start_background_task(mongo.upload, i_collection, parameters, interference_model) - logger.info(f"Generated new interference model with parameters: {parameters}") + emit_status(f"Generated new interference model with parameters: {parameters}") else: - logger.info(f"Retrieved existing interference model with parameters: {parameters}") + emit_status(f"Retrieved existing interference model with parameters: {parameters}") return interference_model except Exception as e: logger.error(f"Error generating interference model: {str(e)}", exc_info=True) @@ -193,7 +189,9 @@ def Qfouriertransform(): @socketio.on('connect') def handle_connect(): - logger.info("Client connected") + global sid + sid = request.sid + logger.debug("Client connected") emit('status_update', {'message': 'Connected to quantum model generator server'}) @socketio.on('disconnect') @@ -202,9 +200,9 @@ def handle_disconnect(): @socketio.on('message') def handle_message(data): - logger.info(f"Received message: {data}") + logger.debug(f"Received message: {data}") if __name__ == '__main__': app.debug = True - logger.info("Starting quantum modeling server") - socketio.run(app, host="0.0.0.0", port=3001, debug=True) \ No newline at end of file + logger.debug("Starting quantum modeling server") + socketio.run(app, host="0.0.0.0", port=3001, debug=False) \ No newline at end of file diff --git a/quantum_app_backend/requirements.txt b/quantum_app_backend/requirements.txt index 5069fba..50b3195 100644 --- a/quantum_app_backend/requirements.txt +++ b/quantum_app_backend/requirements.txt @@ -28,5 +28,4 @@ flask-pymongo dotenv flask-socketio gunicorn==23.0.0 -eventlet==0.39.1 -greenlet==3.1.1 \ No newline at end of file +gevent==24.11.1 \ No newline at end of file From 3bae1a207bc90b7360bdc151f116358144f417de Mon Sep 17 00:00:00 2001 From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com> Date: Thu, 27 Mar 2025 23:52:18 -0400 Subject: [PATCH 2/2] don't log html to console --- src/pages/Interference.tsx | 1 - src/pages/SingleQgate.tsx | 1 - src/pages/Tunneling.tsx | 5 +++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/Interference.tsx b/src/pages/Interference.tsx index fad5617..d91e56c 100644 --- a/src/pages/Interference.tsx +++ b/src/pages/Interference.tsx @@ -111,7 +111,6 @@ const Interference = () => { .then((response) => response.text()) .then((text) => { setAnimationJsHtml(text); - console.log(text); }); } catch (error) { console.error("Failed to load default HTML content:", error); diff --git a/src/pages/SingleQgate.tsx b/src/pages/SingleQgate.tsx index 8e203ea..3167f35 100644 --- a/src/pages/SingleQgate.tsx +++ b/src/pages/SingleQgate.tsx @@ -93,7 +93,6 @@ const SpinTraceEvolution = () => { .then((response) => response.text()) .then((text) => { setAnimationJsHtml(text); - console.log(text) }); } catch (error) { console.error('Failed to load default HTML content:', error); diff --git a/src/pages/Tunneling.tsx b/src/pages/Tunneling.tsx index ba14448..3452b14 100644 --- a/src/pages/Tunneling.tsx +++ b/src/pages/Tunneling.tsx @@ -59,7 +59,9 @@ const Tunneling = () => { // ========= socket connection ========= useEffect(() => { - const socket = io(host); + const socket = io(host, { + transports: ['websocket'] + }); socket.on("connect", () => { console.log("Connected to server"); @@ -113,7 +115,6 @@ const Tunneling = () => { .then((response) => response.text()) .then((text) => { setAnimationJsHtml(text); - console.log(text); }); } catch (error) { setSnackbarMessage("Failed to load default model.");