Search code examples
pythonflaskpython-requestscountdown

Python Flask update var after new request


I have created a simple script in Python (i am a newby). Everything is working as needed, except for one minor issue.

My project: I send a request to my server through http: {ip-of-server}/?speed=999&time=8&cents=50

This will display a countdown timer in your shell. Counting down from 8 to 0 in this case. That works well. When I send {ip-of-server}/?speed=499&time=8&cents=50 it will count down twice as fast. This is as needed.

The issue i am facing: During countdown, i need to be able to send a new request to my server. It should update the countdown with the new values. At the moment it will create 2 countdowns. Which is correct if you read the script, but not what I need. I need some help how to just update the existing countdown.

My code:

from flask import Flask, request
app = Flask(__name__)
import time

@app.route('/', methods = ["GET"])

def post():
    speed = float(request.args["speed"])
    thetime = request.args["time"]
    cents = request.args["cents"]

    print('\n')
    print('AccuView Digital:')
    print('Speed:', speed,' Time:', thetime,' Cents:', cents)
    print('-------------------------------')

    def countdown(thetime):
        while thetime:
            mins, secs = divmod(thetime, 60)
            timer = '{:02d}:{:02d}'.format(mins, secs)
            print('Tijd:', timer, end="\r")
            time.sleep((speed+1)/1000)
            thetime -= 1
            if thetime == 0:
                print('Werp geld in\n') 
    countdown(int(thetime))
    return '1'

app.run(host='192.168.1.107', port= 8090)

Thanks


Solution

  • The script is working fine as you said yourself. So what's happening right now is that flask is creating threads to serve your requests. You send 1st request, flask starts a counter on one thread and when you send another request, flask starts another thread and another counter runs on that thread. Both threads have their own values of speed, thetime and cents and one thread cannot change the value of a variable in another thread.

    So what we want to do is to access/modify the value of variables from any thread. One easy solution for this is to use global variables so that these variables are accessible from all the threads.

    Solution:

    1. Make speed, thetime and cents as global variables so they are modifiable from any thread.
    2. When we receive a request, check if a counter is already running (we can do it by checking if value of global variable thetime is 0).
    3. We know if an existing counter is running or not, now just update the values of global variables.
    4. If there is no existing counter running, then start the counter (call the method countdown()). Else we don't need to do anything (we have already updated the values of global variables in previous step so the existing counter is updated).

    Code:

    import time
    from flask import Flask, request
    
    app = Flask(__name__)
    
    # We create global variables to keep track of the counter
    speed = thetime = cents = 0
    
    
    @app.route('/', methods=["GET"])
    def post():
        global speed, thetime, cents
    
        # Check if previous counter is running
        counter_running = True if thetime else False
    
        thetime = int(request.args["time"])
        speed = float(request.args["speed"])
        cents = request.args["cents"]
    
        print('\n')
        print('AccuView Digital:')
        print('Speed:', speed, ' Time:', thetime, ' Cents:', cents)
        print('-------------------------------')
    
        def countdown():
            global thetime, speed
            while thetime:
                mins, secs = divmod(thetime, 60)
                timer = '{:02d}:{:02d}'.format(mins, secs)
                print('Tijd:', timer, end="\r")
                time.sleep((speed + 1) / 1000)
                thetime -= 1
                if thetime == 0:
                    print('Werp geld in\n')
    
        # If existing counter is running, then we don't start another counter
        if not counter_running:
            countdown()
        return '1'
    
    
    app.run(host='192.168.1.107', port= 8090)
    

    Code (so that we can interrupt sleep):

    import time
    import threading
    from flask import Flask, request
    
    app = Flask(__name__)
    
    # We create global variables to keep track of the counter
    speed = thetime = cents = 0
    sleep_speed = threading.Event()
    
    
    @app.route('/', methods=["GET"])
    def post():
        global speed, thetime, cents, sleep_speed
    
        # Check if previous counter is running
        counter_running = True if thetime else False
    
        thetime = int(request.args["time"])
        speed = float(request.args["speed"])
        cents = request.args["cents"]
    
        # Make sure to interrupt counter's sleep
        if not sleep_speed.is_set():
            sleep_speed.set()
        sleep_speed.clear()
    
        print('\n')
        print('AccuView Digital:')
        print('Speed:', speed, ' Time:', thetime, ' Cents:', cents)
        print('-------------------------------')
    
        def countdown():
            global thetime, speed
            while thetime:
                mins, secs = divmod(thetime, 60)
                timer = '{:02d}:{:02d}'.format(mins, secs)
                print('Tijd:', timer, end="\r")
                sleep_speed.wait((speed + 1) / 1000)
                thetime -= 1
                if thetime == 0:
                    print('Werp geld in\n')
    
        # If existing counter is running, then we don't start another counter
        if not counter_running:
            countdown()
        return '1'
    
    
    app.run(host='0.0.0.0', port=8090)