0

I have turned one of my manual scripts into a backend using flask. If I am to run this script from the terminal for testing it python3 app.py, it runs the checkRouter() function twice. I am not sure why this is happening, can someone please advise me?

import buttonshim
import datetime
import flask
import json
import subprocess
import threading
import time


routerCheck  = ""
script       = ""
switchButton = True
switchCheck  = True


thisJson = {
    "thisName": "none",
    "thisTime": "0",
    "executed": ""
}




## Script
def blinkButton():
    def run():
        while (switchButton == True):
            buttonshim.set_pixel(0x00, 0xff, 0x00)
            time.sleep(.2)
            buttonshim.set_pixel(0,0,0)
            time.sleep(.2)
            if switchButton == False:
                break
            if script.poll() is not None:
                switchButton == False
                break
    thread = threading.Thread(target=run)
    thread.start()

def blinkButtonCheck():
    def run():
        while (switchCheck == True):
            buttonshim.set_pixel(0x00, 0x00, 0xff)
            time.sleep(.2)
            buttonshim.set_pixel(0,0,0)
            time.sleep(.2)
            if switchCheck == False:
                break
            if routerCheck.poll() is not None:
                switchCheck == False
                break
    thread = threading.Thread(target=run)
    thread.start()

def switchOn():
    global switchButton
    global script
    global thisJson
    try:
        if script.poll() is None:
            script.kill()
            switchButton = False
    except:
        print("Process still running, killing...")
    finally:
        print("switchButton on")
        if thisJson["thisName"] == "none":
            print("No name set")
        else:
            switchButton         = True
            thisJson["executed"] = str(datetime.datetime.now())
            script               = subprocess.Popen(['/home/flask/run.sh', thisJson["thisName"], thisJson["thisTime"]])
            blinkButton()

def switchOff():
    global switchButton
    global script
    global thisJson
    try:
        print("switchButton off")
        switchButton = False
        script.kill()
        buttonshim.set_pixel(0xff, 0x00, 0x00)
        time.sleep(2)
        buttonshim.set_pixel(0,0,0)
        thisJson = {
            "thisName": "none",
            "thisTime": "0",
            "executed": ""
        }
    except:
        print("Process not running")
        thisJson = {
            "thisName": "none",
            "thisTime": "0",
            "executed": ""
        }

def checkChannel():
    global switchCheck
    global routerCheck
    try:
        if routerCheck.poll() is None:
            routerCheck.kill()
            switchCheck = False
    except:
        print("Process still running, killing...")
    finally:
        print("switchCheck on")
        switchCheck = True
        routerCheck = subprocess.Popen(['/home/flask/run.sh', 'check'])
        blinkButtonCheck()

# run router check every half hour
def checkRouter():
    print("Initial router check")
    def runCheck():
        while True:
            checkChannel()
            time.sleep(1800)
    threadCheck = threading.Thread(target=runCheck)
    threadCheck.start()





## Flask
app = flask.Flask(__name__)

@app.route('/api/get', methods=['GET'])
def get():
    global thisJson
    print("\n{}\nOBJECTMAKER: {}\n".format(datetime.datetime.now(), thisJson))
    return json.dumps(thisJson)

@app.route('/api/<set>', methods=['GET', 'POST'])
def kill(set):
    global thisJson
    content  = flask.request.json
    print(content)
    thisJson["thisName"] = content["thisName"]
    thisJson["thisTime"] = content["thisTime"]
    switchOn()
    return json.dumps(True)


@app.route('/api/stop', methods=['POST'])
def stop():
    switchOff()
    return json.dumps(True)

if __name__ == '__main__':
    checkRouter()
    app.run(host="0.0.0.0", port=5001, debug=True)


As you can see from below, Initial router check and switchCheck on is printed twice, meaning it gets called twice. Before wrapping Flask around it I never had this issue, but I was using a basic pause() at the end, after loading buttons scripts (removed from this new script). Note, sudo is required for buttonshim to work properly.

└─$ sudo python3 ./app.py
Initial router check
Process still running, killing...
switchCheck on
Killing wireless processes
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on

 * Running on http://0.0.0.0:5001/ (Press CTRL+C to quit)
 * Restarting with stat
Initial router check
Process still running, killing...
switchCheck on
Killing wireless processes
 * Debugger is active!
 * Debugger PIN: 171-605-250

^C^CException ignored in: <module 'threading' from '/usr/lib/python3.10/threading.py'>
Traceback (most recent call last):
  File "/usr/lib/python3.10/threading.py", line 1567, in _shutdown
    lock.acquire()
KeyboardInterrupt:
davidism
  • 121,510
  • 29
  • 395
  • 339
Beefcake
  • 733
  • 2
  • 12
  • 37
  • interesting... are you sure run.sh doesnt execute the app.py file again? we might have to look at this code - if you are sure it's completely unrelated, you may as well exclude it from your question. are you opening app.py via console? it might also be your IDE spawning another instance – c8999c 3f964f64 Oct 10 '22 at 08:38
  • i'm 100% confident `run.sh` does not execute `app.py` again. i am executing `app.py` from my zsh terminal. using `ps -aux` i can see multiple instances of `run.sh` executing, but as you can see from the log output, even before it runs that, the `checkRouter()` shows it was executed twice. so the issue is well before `run.sh` executes. it's within Python script. – Beefcake Oct 10 '22 at 10:39

1 Answers1

0

What I tried and solved the issue is to use a WSGI instead of the debug one that flask provides. For example, instead of running your app with python app.py, I used gunicorn app:app more on gunicorn configuration can be found here. For that to work you also need to add checkRouter() outside the if __name__ == '__main__': (I know this sounds like a bad practice, but if you run it with gunicorn it does not go through __main__).

  • I removed the `debug=True`, and it fixed the issue. not sure what the go is, but it's as if a file is modified and thus it re-runs the flask server. I'm not sure if that's directly related to your last comment about threads; if it was I would mark this is as correct. Thoughts? – Beefcake Oct 10 '22 at 11:55
  • It's just a guess, and since I am not familiar with the default debug server implementation, I will remove it from the answer. – Kyriakos Psarakis Oct 10 '22 at 12:54