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.

Asked By: vic

||

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.

Answered By: Zorayr

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..."
Answered By: danvk

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
Answered By: Nam G VU

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.

Answered By: jogco

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.

Answered By: Ruben Decrop

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
Answered By: R J

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

  1. Goto Task Manager
  2. Find flask.exe
  3. Select and End process
Answered By: Sumit Bajaj

You can use method bellow

app.do_teardown_appcontext()
Answered By: Alex

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)

Answered By: kip2

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
Answered By: Deg

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)
Answered By: publicapps

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.

Answered By: Rohit Singh

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://0.0.0.0:5001/shutdown')
Answered By: QtRoS

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.

Answered By: D Left Adjoint to U

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)
Answered By: Baris Senyerli
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"
Answered By: user3076105

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.

How to kill a process running on particular port in Linux?

Answered By: TJF

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.

Answered By: Lampe2020
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.