[python] How to stop flask application without using ctrl-c

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.

This question is related to python flask flask-extensions

The answer is


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:

  1. 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)
  2. 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://localhost:5001/shutdown')

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)


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'\r\n'

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.


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.srv = make_server('127.0.0.1', 5000, app)
        self.ctx = app.app_context()
        self.ctx.push()

    def run(self):
        log.info('starting server')
        self.srv.serve_forever()

    def shutdown(self):
        self.srv.shutdown()

def start_server():
    global server
    app = flask.Flask('myapp')
    ...
    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

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

You can use method bellow

app.do_teardown_appcontext()

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)

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.


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.


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

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.route('/seriouslykill', methods=['POST'])
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.route('/kill', methods=['POST'])
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..."

For Windows, it is quite easy to stop/kill flask server -

  1. Goto Task Manager
  2. Find flask.exe
  3. Select and End process