jamesroberts / fastwsgi

An ultra fast WSGI server for Python 3
Other
439 stars 14 forks source link

fastwsgi blocks OTHER threads from executing #51

Open ibrewster opened 11 months ago

ibrewster commented 11 months ago

Calling fastwsgi.run should block the main thread, but release the GIL, allowing other threads to run (I/O wait). However, the observed behavior is that all threads are blocked, implying the GIL is not released while fastwsgi is waiting (though the actual issue may be different).

Observe the difference in behavior with this toy code when using fastwsgi.run vs. the development flask app.run

import threading, time
import fastwsgi

from flask import Flask

app = Flask(__name__)

@app.get('/')
def hello_world():
    return 'Hello, World!', 200

def dummy_thread():
    while True:
        print("Staying alive!")
        time.sleep(1)

if __name__ == '__main__':
    thread = threading.Thread(target=dummy_thread)
    thread.start()
    time.sleep(3) # Should print "Staying alive!" a number of times

    # This should block the main thread, but the "staying alive" thread should keep running
    # Using fastwsgi, all stops.
    fastwsgi.run(wsgi_app=app, host='0.0.0.0', port=5000)

    # Using the flask provided development server, the other thread continues as expected.
    # app.run(host='0.0.0.0', port=5000)

In many (most?) apps this would not be an issue, however it makes fastwsgi unusable in any application that requires some sort of background processing, such as my RaspberryPi app that provides a web server, but also listens for button presses.

remittor commented 10 months ago
import threading, time
import fastwsgi

from flask import Flask

app = Flask(__name__)

@app.get('/')
def hello_world():
    return 'Hello, World!', 200

def dummy_thread():
    while True:
        print("Staying alive!")
        time.sleep(1)

if __name__ == '__main__':
    thread = threading.Thread(target = dummy_thread)
    thread.start()
    time.sleep(3) # Should print "Staying alive!" a number of times

    srv = fastwsgi.server
    srv.host = '0.0.0.0'
    srv.port = 5000
    srv.loglevel = 6
    #srv.allow_keepalive = 0
    srv.hook_sigint = 1   # intercepting the SIGINT signal inside the REST API request handler
    srv.nowait = 2        # enabling periodic maintenance of REST API requests
    rc = srv.init(app)
    if rc != 0:
        print(f"ERROR: cannot init REST API server (err = {rc})")
        exit(rc)

    print(f"REST API server listening at http://{srv.host}:{srv.port}")

    while True:
        # processing REST API requests
        rc = srv.run()
        if rc != 0:
            print(f"REST API return code = {rc}")
            break
        # asynchronous task execution (without waiting for a REST API request)
        # do something in background
        time.sleep(0)

    srv.close()
    print("===== FastWSGI server finish =====")
Louciole commented 4 months ago

Hi guys ! I have the same issue as ibrewster, i would like to be able to run some websockets in the background, I understand that i can unblock my GIL with the proposed solution, but I have some issue with it :

Is there a cleaner solution ?

remittor commented 4 months ago

@Louciole , look this func: https://github.com/jamesroberts/fastwsgi/blob/5572bb31b859d690be225707b9e7e25af397544b/fastwsgi/server.c#L924