How can I add a background thread to flask? How can I add a background thread to flask? python python

How can I add a background thread to flask?


Your additional threads must be initiated from the same app that is called by the WSGI server.

The example below creates a background thread that executes every 5 seconds and manipulates data structures that are also available to Flask routed functions.

import threadingimport atexitfrom flask import FlaskPOOL_TIME = 5 #Seconds    # variables that are accessible from anywherecommonDataStruct = {}# lock to control access to variabledataLock = threading.Lock()# thread handleryourThread = threading.Thread()def create_app():    app = Flask(__name__)    def interrupt():        global yourThread        yourThread.cancel()    def doStuff():        global commonDataStruct        global yourThread        with dataLock:            pass            # Do your stuff with commonDataStruct Here        # Set the next thread to happen        yourThread = threading.Timer(POOL_TIME, doStuff, ())        yourThread.start()       def doStuffStart():        # Do initialisation stuff here        global yourThread        # Create your thread        yourThread = threading.Timer(POOL_TIME, doStuff, ())        yourThread.start()    # Initiate    doStuffStart()    # When you kill Flask (SIGTERM), clear the trigger for the next thread    atexit.register(interrupt)    return appapp = create_app()          

Call it from Gunicorn with something like this:

gunicorn -b 0.0.0.0:5000 --log-config log.conf --pid=app.pid myfile:app


In addition to using pure threads or the Celery queue (note that flask-celery is no longer required), you could also have a look at flask-apscheduler:

https://github.com/viniciuschiele/flask-apscheduler

A simple example copied from https://github.com/viniciuschiele/flask-apscheduler/blob/master/examples/jobs.py:

from flask import Flaskfrom flask_apscheduler import APSchedulerclass Config(object):    JOBS = [        {            'id': 'job1',            'func': 'jobs:job1',            'args': (1, 2),            'trigger': 'interval',            'seconds': 10        }    ]    SCHEDULER_API_ENABLED = Truedef job1(a, b):    print(str(a) + ' ' + str(b))if __name__ == '__main__':    app = Flask(__name__)    app.config.from_object(Config())    scheduler = APScheduler()    # it is also possible to enable the API directly    # scheduler.api_enabled = True    scheduler.init_app(app)    scheduler.start()    app.run()


First, you should use any WebSocket or polling mechanics to notify the frontend part about changes that happened. I use Flask-SocketIO wrapper, and very happy with async messaging for my tiny apps.

Nest, you can do all logic which you need in a separate thread(s), and notify the frontend via SocketIO object (Flask holds continuous open connection with every frontend client).

As an example, I just implemented page reload on backend file modifications:

<!doctype html><script>    sio = io()    sio.on('reload',(info)=>{        console.log(['sio','reload',info])        document.location.reload()    })</script>
class App(Web, Module):    def __init__(self, V):        ## flask module instance        self.flask = flask        ## wrapped application instance        self.app = flask.Flask(self.value)        self.app.config['SECRET_KEY'] = config.SECRET_KEY        ## `flask-socketio`        self.sio = SocketIO(self.app)        self.watchfiles()    ## inotify reload files after change via `sio(reload)``    def watchfiles(self):        from watchdog.observers import Observer        from watchdog.events import FileSystemEventHandler        class Handler(FileSystemEventHandler):            def __init__(self,sio):                super().__init__()                self.sio = sio            def on_modified(self, event):                print([self.on_modified,self,event])                self.sio.emit('reload',[event.src_path,event.event_type,event.is_directory])        self.observer = Observer()        self.observer.schedule(Handler(self.sio),path='static',recursive=True)        self.observer.schedule(Handler(self.sio),path='templates',recursive=True)        self.observer.start()