How to stop flask application without using ctrl-c
Question:
I want to implement a command which can stop flask application by using flask-script.
I have searched the solution for a while. Because the framework doesn’t provide app.stop()
API, I am curious about how to code this. I am working on Ubuntu 12.10 and Python 2.7.3.
Answers:
If you are just running the server on your desktop, you can expose an endpoint to kill the server (read more at Shutdown The Simple Server):
from flask import request
def shutdown_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
@app.get('/shutdown')
def shutdown():
shutdown_server()
return 'Server shutting down...'
Here is another approach that is more contained:
from multiprocessing import Process
server = Process(target=app.run)
server.start()
# ...
server.terminate()
server.join()
Let me know if this helps.
As others have pointed out, you can only use werkzeug.server.shutdown
from a request handler. The only way I’ve found to shut down the server at another time is to send a request to yourself. For example, the /kill
handler in this snippet will kill the dev server unless another request comes in during the next second:
import requests
from threading import Timer
from flask import request
import time
LAST_REQUEST_MS = 0
@app.before_request
def update_last_request_ms():
global LAST_REQUEST_MS
LAST_REQUEST_MS = time.time() * 1000
@app.post('/seriouslykill')
def seriouslykill():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
return "Shutting down..."
@app.post('/kill')
def kill():
last_ms = LAST_REQUEST_MS
def shutdown():
if LAST_REQUEST_MS <= last_ms: # subsequent requests abort shutdown
requests.post('http://localhost:5000/seriouslykill')
else:
pass
Timer(1.0, shutdown).start() # wait 1 second
return "Shutting down..."
My method can be proceeded via bash terminal/console
1) run and get the process number
$ ps aux | grep yourAppKeywords
2a) kill the process
$ kill processNum
2b) kill the process if above not working
$ kill -9 processNum
This is an old question, but googling didn’t give me any insight in how to accomplish this.
Because I didn’t read the code here properly! (Doh!)
What it does is to raise a RuntimeError
when there is no werkzeug.server.shutdown
in the request.environ
…
So what we can do when there is no request
is to raise a RuntimeError
def shutdown():
raise RuntimeError("Server going down")
and catch that when app.run()
returns:
...
try:
app.run(host="0.0.0.0")
except RuntimeError, msg:
if str(msg) == "Server going down":
pass # or whatever you want to do when the server goes down
else:
# appropriate handling/logging of other runtime errors
# and so on
...
No need to send yourself a request.
I did it slightly different using threads
from werkzeug.serving import make_server
class ServerThread(threading.Thread):
def __init__(self, app):
threading.Thread.__init__(self)
self.server = make_server('127.0.0.1', 5000, app)
self.ctx = app.app_context()
self.ctx.push()
def run(self):
log.info('starting server')
self.server.serve_forever()
def shutdown(self):
self.server.shutdown()
def start_server():
global server
app = flask.Flask('myapp')
# App routes defined here
server = ServerThread(app)
server.start()
log.info('server started')
def stop_server():
global server
server.shutdown()
I use it to do end to end tests for restful api, where I can send requests using the python requests library.
This is a bit old thread, but if someone experimenting, learning, or testing basic flask app, started from a script that runs in the background, the quickest way to stop it is to kill the process running on the port you are running your app on.
Note: I am aware the author is looking for a way not to kill or stop the app. But this may help someone who is learning.
sudo netstat -tulnp | grep :5001
You’ll get something like this.
tcp 0 0 0.0.0.0:5001 0.0.0.0:* LISTEN 28834/python
To stop the app, kill the process
sudo kill 28834
For Windows, it is quite easy to stop/kill flask server –
- Goto Task Manager
- Find flask.exe
- Select and End process
You can use method bellow
app.do_teardown_appcontext()
If you’re working on the CLI and only have one flask app/process running (or rather, you just want want to kill any flask process running on your system), you can kill it with:
kill $(pgrep -f flask)
You don’t have to press CTRL + C, but you can provide an endpoint which does it for you:
from flask import Flask, jsonify, request
import json, os, signal
@app.route('/stopServer', methods=['GET'])
def stopServer():
os.kill(os.getpid(), signal.SIGINT)
return jsonify({ "success": True, "message": "Server is shutting down..." })
Now you can just call this endpoint to gracefully shutdown the server:
curl localhost:5000/stopServer
If you’re outside the request-response handling, you can still:
import os
import signal
sig = getattr(signal, "SIGKILL", signal.SIGTERM)
os.kill(os.getpid(), sig)
Google Cloud VM instance + Flask App
I hosted my Flask Application on Google Cloud Platform Virtual Machine.
I started the app using python main.py
But the problem was ctrl+c did not work to stop the server.
This command $ sudo netstat -tulnp | grep :5000
terminates the server.
My Flask app runs on port 5000 by default.
Note: My VM instance is running on Linux 9.
It works for this. Haven’t tested for other platforms.
Feel free to update or comment if it works for other versions too.
If someone else is looking how to stop Flask server inside win32 service – here it is. It’s kinda weird combination of several approaches, but it works well. Key ideas:
- These is
shutdown
endpoint which can be used for graceful shutdown. Note: it relies on request.environ.get
which is usable only inside web request’s context (inside @app.route
-ed function)
- win32service’s
SvcStop
method uses requests
to do HTTP request to the service itself.
myservice_svc.py
import win32service
import win32serviceutil
import win32event
import servicemanager
import time
import traceback
import os
import myservice
class MyServiceSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "MyServiceSvc" # NET START/STOP the service by the following name
_svc_display_name_ = "Display name" # this text shows up as the service name in the SCM
_svc_description_ = "Description" # this text shows up as the description in the SCM
def __init__(self, args):
os.chdir(os.path.dirname(myservice.__file__))
win32serviceutil.ServiceFramework.__init__(self, args)
def SvcDoRun(self):
# ... some code skipped
myservice.start()
def SvcStop(self):
"""Called when we're being shut down"""
myservice.stop()
# tell the SCM we're shutting down
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
if __name__ == '__main__':
os.chdir(os.path.dirname(myservice.__file__))
win32serviceutil.HandleCommandLine(MyServiceSvc)
myservice.py
from flask import Flask, request, jsonify
# Workaround - otherwise doesn't work in windows service.
cli = sys.modules['flask.cli']
cli.show_server_banner = lambda *x: None
app = Flask('MyService')
# ... business logic endpoints are skipped.
@app.route("/shutdown", methods=['GET'])
def shutdown():
shutdown_func = request.environ.get('werkzeug.server.shutdown')
if shutdown_func is None:
raise RuntimeError('Not running werkzeug')
shutdown_func()
return "Shutting down..."
def start():
app.run(host='0.0.0.0', threaded=True, port=5001)
def stop():
import requests
resp = requests.get('http://0.0.0.0:5001/shutdown')
A Python solution
Run with: python kill_server.py
.
This is for Windows only. Kills the servers with taskkill, by PID, gathered with netstat.
# kill_server.py
import os
import subprocess
import re
port = 5000
host = '127.0.0.1'
cmd_newlines = r'rn'
host_port = host + ':' + str(port)
pid_regex = re.compile(r'[0-9]+$')
netstat = subprocess.run(['netstat', '-n', '-a', '-o'], stdout=subprocess.PIPE)
# Doesn't return correct PID info without precisely these flags
netstat = str(netstat)
lines = netstat.split(cmd_newlines)
for line in lines:
if host_port in line:
pid = pid_regex.findall(line)
if pid:
pid = pid[0]
os.system('taskkill /F /PID ' + str(pid))
# And finally delete the .pyc cache
os.system('del /S *.pyc')
If you are having trouble with favicon / changes to index.html loading (i.e. old versions are cached), then try "Clear Browsing Data > Images & Files" in Chrome as well.
Doing all the above, and I got my favicon to finally load upon running my Flask app.
request.environ.get
deprecated.
Pavel Minaev solution is pretty clear:
import os
from flask import Flask
app = Flask(__name__)
exiting = False
@app.route("/exit")
def exit_app():
global exiting
exiting = True
return "Done"
@app.teardown_request
def teardown(exception):
if exiting:
os._exit(0)
app = MyFlaskSubclass()
...
app.httpd = MyWSGIServerSubclass()
...
@app.route('/shutdown')
def app_shutdown():
from threading import Timer
t = Timer(5, app.httpd.shutdown)
t.start()
return "Server shut down"
My bash script variant (LINUX):
#!/bin/bash
portFind="$1"
echo "Finding process on port: $portFind"
pid=$(netstat -tulnp | grep :"$1" | awk '{print $7}' | cut -f1 -d"/")
echo "Process found: $pid"
kill -9 $pid
echo "Process $pid killed"
Usage example:
sudo bash killWebServer.sh 2223
Output:
Finding process on port: 2223
Process found: 12706
Process 12706 killed
If the port is known (e.g., 5000) a simple solution I have found is to enter:
fuser -k 5000/tcp
this will kill the process on port 5000.
I found that killing the own PID seems to work, like follows:
import os
from flask import Flask
app = Flask(__name__)
own_pid = os.getpid() # Get the main process's PID in a global variable
@app.route('/kill-backend')
def kill_backend():
global own_pid # Make sure to use the global variable
os.kill(own_pid, 9) # The second argument is the signal, 9 stands for SIGKILL.
#If you want to "politely ask" the server to quit you can use SIGQUIT (15) instead.
app.run(host='0.0.0.0', port=8000)
I have tested this on Ubuntu 22.04 LTS and on Window$ 10. It works on both.
To trigger the server kill, just request http://127.0.0.1/kill-backend
and it’ll fail with a connection refused
error because the server is immediately dead.
I want to implement a command which can stop flask application by using flask-script.
I have searched the solution for a while. Because the framework doesn’t provide app.stop()
API, I am curious about how to code this. I am working on Ubuntu 12.10 and Python 2.7.3.
If you are just running the server on your desktop, you can expose an endpoint to kill the server (read more at Shutdown The Simple Server):
from flask import request
def shutdown_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
@app.get('/shutdown')
def shutdown():
shutdown_server()
return 'Server shutting down...'
Here is another approach that is more contained:
from multiprocessing import Process
server = Process(target=app.run)
server.start()
# ...
server.terminate()
server.join()
Let me know if this helps.
As others have pointed out, you can only use werkzeug.server.shutdown
from a request handler. The only way I’ve found to shut down the server at another time is to send a request to yourself. For example, the /kill
handler in this snippet will kill the dev server unless another request comes in during the next second:
import requests
from threading import Timer
from flask import request
import time
LAST_REQUEST_MS = 0
@app.before_request
def update_last_request_ms():
global LAST_REQUEST_MS
LAST_REQUEST_MS = time.time() * 1000
@app.post('/seriouslykill')
def seriouslykill():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
return "Shutting down..."
@app.post('/kill')
def kill():
last_ms = LAST_REQUEST_MS
def shutdown():
if LAST_REQUEST_MS <= last_ms: # subsequent requests abort shutdown
requests.post('http://localhost:5000/seriouslykill')
else:
pass
Timer(1.0, shutdown).start() # wait 1 second
return "Shutting down..."
My method can be proceeded via bash terminal/console
1) run and get the process number
$ ps aux | grep yourAppKeywords
2a) kill the process
$ kill processNum
2b) kill the process if above not working
$ kill -9 processNum
This is an old question, but googling didn’t give me any insight in how to accomplish this.
Because I didn’t read the code here properly! (Doh!)
What it does is to raise a RuntimeError
when there is no werkzeug.server.shutdown
in the request.environ
…
So what we can do when there is no request
is to raise a RuntimeError
def shutdown():
raise RuntimeError("Server going down")
and catch that when app.run()
returns:
...
try:
app.run(host="0.0.0.0")
except RuntimeError, msg:
if str(msg) == "Server going down":
pass # or whatever you want to do when the server goes down
else:
# appropriate handling/logging of other runtime errors
# and so on
...
No need to send yourself a request.
I did it slightly different using threads
from werkzeug.serving import make_server
class ServerThread(threading.Thread):
def __init__(self, app):
threading.Thread.__init__(self)
self.server = make_server('127.0.0.1', 5000, app)
self.ctx = app.app_context()
self.ctx.push()
def run(self):
log.info('starting server')
self.server.serve_forever()
def shutdown(self):
self.server.shutdown()
def start_server():
global server
app = flask.Flask('myapp')
# App routes defined here
server = ServerThread(app)
server.start()
log.info('server started')
def stop_server():
global server
server.shutdown()
I use it to do end to end tests for restful api, where I can send requests using the python requests library.
This is a bit old thread, but if someone experimenting, learning, or testing basic flask app, started from a script that runs in the background, the quickest way to stop it is to kill the process running on the port you are running your app on.
Note: I am aware the author is looking for a way not to kill or stop the app. But this may help someone who is learning.
sudo netstat -tulnp | grep :5001
You’ll get something like this.
tcp 0 0 0.0.0.0:5001 0.0.0.0:* LISTEN 28834/python
To stop the app, kill the process
sudo kill 28834
For Windows, it is quite easy to stop/kill flask server –
- Goto Task Manager
- Find flask.exe
- Select and End process
You can use method bellow
app.do_teardown_appcontext()
If you’re working on the CLI and only have one flask app/process running (or rather, you just want want to kill any flask process running on your system), you can kill it with:
kill $(pgrep -f flask)
You don’t have to press CTRL + C, but you can provide an endpoint which does it for you:
from flask import Flask, jsonify, request
import json, os, signal
@app.route('/stopServer', methods=['GET'])
def stopServer():
os.kill(os.getpid(), signal.SIGINT)
return jsonify({ "success": True, "message": "Server is shutting down..." })
Now you can just call this endpoint to gracefully shutdown the server:
curl localhost:5000/stopServer
If you’re outside the request-response handling, you can still:
import os
import signal
sig = getattr(signal, "SIGKILL", signal.SIGTERM)
os.kill(os.getpid(), sig)
Google Cloud VM instance + Flask App
I hosted my Flask Application on Google Cloud Platform Virtual Machine.
I started the app using python main.py
But the problem was ctrl+c did not work to stop the server.
This command $ sudo netstat -tulnp | grep :5000
terminates the server.
My Flask app runs on port 5000 by default.
Note: My VM instance is running on Linux 9.
It works for this. Haven’t tested for other platforms.
Feel free to update or comment if it works for other versions too.
If someone else is looking how to stop Flask server inside win32 service – here it is. It’s kinda weird combination of several approaches, but it works well. Key ideas:
- These is
shutdown
endpoint which can be used for graceful shutdown. Note: it relies onrequest.environ.get
which is usable only inside web request’s context (inside@app.route
-ed function) - win32service’s
SvcStop
method usesrequests
to do HTTP request to the service itself.
myservice_svc.py
import win32service
import win32serviceutil
import win32event
import servicemanager
import time
import traceback
import os
import myservice
class MyServiceSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "MyServiceSvc" # NET START/STOP the service by the following name
_svc_display_name_ = "Display name" # this text shows up as the service name in the SCM
_svc_description_ = "Description" # this text shows up as the description in the SCM
def __init__(self, args):
os.chdir(os.path.dirname(myservice.__file__))
win32serviceutil.ServiceFramework.__init__(self, args)
def SvcDoRun(self):
# ... some code skipped
myservice.start()
def SvcStop(self):
"""Called when we're being shut down"""
myservice.stop()
# tell the SCM we're shutting down
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
if __name__ == '__main__':
os.chdir(os.path.dirname(myservice.__file__))
win32serviceutil.HandleCommandLine(MyServiceSvc)
myservice.py
from flask import Flask, request, jsonify
# Workaround - otherwise doesn't work in windows service.
cli = sys.modules['flask.cli']
cli.show_server_banner = lambda *x: None
app = Flask('MyService')
# ... business logic endpoints are skipped.
@app.route("/shutdown", methods=['GET'])
def shutdown():
shutdown_func = request.environ.get('werkzeug.server.shutdown')
if shutdown_func is None:
raise RuntimeError('Not running werkzeug')
shutdown_func()
return "Shutting down..."
def start():
app.run(host='0.0.0.0', threaded=True, port=5001)
def stop():
import requests
resp = requests.get('http://0.0.0.0:5001/shutdown')
A Python solution
Run with: python kill_server.py
.
This is for Windows only. Kills the servers with taskkill, by PID, gathered with netstat.
# kill_server.py
import os
import subprocess
import re
port = 5000
host = '127.0.0.1'
cmd_newlines = r'rn'
host_port = host + ':' + str(port)
pid_regex = re.compile(r'[0-9]+$')
netstat = subprocess.run(['netstat', '-n', '-a', '-o'], stdout=subprocess.PIPE)
# Doesn't return correct PID info without precisely these flags
netstat = str(netstat)
lines = netstat.split(cmd_newlines)
for line in lines:
if host_port in line:
pid = pid_regex.findall(line)
if pid:
pid = pid[0]
os.system('taskkill /F /PID ' + str(pid))
# And finally delete the .pyc cache
os.system('del /S *.pyc')
If you are having trouble with favicon / changes to index.html loading (i.e. old versions are cached), then try "Clear Browsing Data > Images & Files" in Chrome as well.
Doing all the above, and I got my favicon to finally load upon running my Flask app.
request.environ.get
deprecated.
Pavel Minaev solution is pretty clear:
import os
from flask import Flask
app = Flask(__name__)
exiting = False
@app.route("/exit")
def exit_app():
global exiting
exiting = True
return "Done"
@app.teardown_request
def teardown(exception):
if exiting:
os._exit(0)
app = MyFlaskSubclass()
...
app.httpd = MyWSGIServerSubclass()
...
@app.route('/shutdown')
def app_shutdown():
from threading import Timer
t = Timer(5, app.httpd.shutdown)
t.start()
return "Server shut down"
My bash script variant (LINUX):
#!/bin/bash
portFind="$1"
echo "Finding process on port: $portFind"
pid=$(netstat -tulnp | grep :"$1" | awk '{print $7}' | cut -f1 -d"/")
echo "Process found: $pid"
kill -9 $pid
echo "Process $pid killed"
Usage example:
sudo bash killWebServer.sh 2223
Output:
Finding process on port: 2223
Process found: 12706
Process 12706 killed
If the port is known (e.g., 5000) a simple solution I have found is to enter:
fuser -k 5000/tcp
this will kill the process on port 5000.
I found that killing the own PID seems to work, like follows:
import os
from flask import Flask
app = Flask(__name__)
own_pid = os.getpid() # Get the main process's PID in a global variable
@app.route('/kill-backend')
def kill_backend():
global own_pid # Make sure to use the global variable
os.kill(own_pid, 9) # The second argument is the signal, 9 stands for SIGKILL.
#If you want to "politely ask" the server to quit you can use SIGQUIT (15) instead.
app.run(host='0.0.0.0', port=8000)
I have tested this on Ubuntu 22.04 LTS and on Window$ 10. It works on both.
To trigger the server kill, just request http://127.0.0.1/kill-backend
and it’ll fail with a connection refused
error because the server is immediately dead.