Reputation: 7268
I am working on python project which includes starting a flask API server
on a button click. For buttons and UI I am using pyqt5
. So on start server button click flask api server will start and on stop server button click, flask api server will stop.
I am able to start the server but the problem is when we start the flask api server, we use app.run(HOST, 80)
. During this the control always remains here and doesnt move out of it due to which when I click stop button, it doesnt stop. Below is the code:
app.py
import sys
import time
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from server import start_local_server
from PyQt5.QtCore import pyqtSlot
from threading import Thread
run = True
def start_api_server():
while run:
start_local_server()
print("server is running")
time.sleep(1)
print("SERVER HAS STOPPED")
class App(QWidget):
global run
def __init__(self):
super().__init__()
self.title = 'PyQt5 button - pythonspot.com'
self.left = 10
self.top = 10
self.width = 320
self.height = 200
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
start_btn = QPushButton('Start Server', self)
start_btn.move(100, 70)
start_btn.clicked.connect(self.on_click_start_btn)
stop_btn = QPushButton('Stop Server', self)
stop_btn.move(200, 70)
stop_btn.clicked.connect(self.on_click_stop_btn)
fun_btn = QPushButton('Click to check responsiveness', self)
fun_btn.move(150, 100)
fun_btn.clicked.connect(self.on_click_fun_btn)
self.show()
@pyqtSlot()
def on_click_start_btn(self):
Thread(target=start_api_server).start()
@pyqtSlot()
def on_click_stop_btn(self):
print("Stop server ")
run = False
@pyqtSlot()
def on_click_fun_btn(self):
print('If it is working, this means UI is responsive')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
In above code, I have button click function on_click_start_btn
this starts a thread with target start_api_server
. This will further start the local flask server. When I want to stop the server, I will simply make run
as False
which will break the start_api_server
function and the server will stop. As per my understanding this should work fine.
Below is the code for flask api:
server.py
import os
import datetime
from flask import Flask, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
wsgi_app = app.wsgi_app
@app.route('/api/status')
def check_status():
return jsonify({'status': 'ok', 'date': datetime.datetime.now().isoformat()}), 200
def start_local_server():
HOST = os.environ.get('SERVER_HOST', 'localhost')
try:
PORT = int(os.environ.get('SERVER_PORT', '5555'))
except ValueError:
PORT = 5555
app.run(HOST, 80)
The problem occurs in above flask code. In above code, there is function start_local_server()
which we are using in app.py
. In this we have app.run()
, when our code reaches here, it always remains here and never moves out it due to which I am not able to stop this server.
I want to simply make code where I can start and stop the flask server using button click but due to app.run
, its not working. Can anyone please help me with this issue. Is there any alternative to above problem. Please help. Thanks
Updated code as per answer:
server = Process
def start_local_server():
global server
server = Process(target=app.run, args=('localhost', 80))
# HOST = os.environ.get('SERVER_HOST', 'localhost')
# try:
# PORT = int(os.environ.get('SERVER_PORT', '5555'))
# except ValueError:
# PORT = 5555
# app.run(HOST, 80)
def stop_local_server():
global server
server.terminate()
Upvotes: 1
Views: 8162
Reputation: 7268
I have resolved the issue by starting the API server in separate thread so that Ui keeps on working. Then I am shutting down the API server using shutdown api
run = True
def start_api_server():
while run:
start_local_server()
time.sleep(1)
print("SERVER HAS STOPPED")
@pyqtSlot()
def on_click_start_btn(self):
Thread(target=start_api_server).start()
Above is the code to start the server on button click. Below is how I am shutting it down:
@pyqtSlot()
def on_click_stop_btn(self):
global run
print("STOPPING SERVER")
run = False
try:
x = requests.get("http://localhost:80/api/shutdown")
rdata = x.text
rdata = json.loads(rdata)
if rdata['status']:
print("Server shutting down")
print(rdata)
except Exception as e:
print(e)
Above code calls a shutdown API which terminate the flask api server. Below is the code for it:
def shutdown_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
@app.route('/api/shutdown')
def shutdown():
shutdown_server()
return 'Server shutting down...'
Upvotes: 0
Reputation: 582
You can run app.run()
in a seperate Process
. Multiprocessing would be helpful in your case, since you're using pyQt.
from multiprocessing import Process
server = Process(target=app.run, args=(HOST, 80))
server.start() # to start the server
server.terminate() # to terminate the server
You can take a deeper look at multiprocessing
library documentation here https://docs.python.org/2/library/multiprocessing.html
You forgot to strart the server :)
server = None
def start_local_server():
global server
server = Process(target=app.run, args=('localhost', 80))
server.start()
# HOST = os.environ.get('SERVER_HOST', 'localhost')
# try:
# PORT = int(os.environ.get('SERVER_PORT', '5555'))
# except ValueError:
# PORT = 5555
# app.run(HOST, 80)
def stop_local_server():
global server
server.terminate()
Upvotes: 2