Search code examples
pythonflaskgunicorngoogle-cloud-run

How to run a Flask sever wrapped in a Class with gunicorn


I am having an issue when running a Flask server with guncicorn where the server code is wrapped in a Class.

Here is my server class:

class WebServer:

    def __init__(self):
        self.app = Flask(__name__)
        self.generateURL()
       
    def generateURL(self):
        self.app.route("/")(self.test)
        self.app.route('/weight', methods=['GET'])(self.receive_weight)
        self.app.route('/usage', methods=['GET'])(self.receive_usage)

   ... 

    def run(self):
        self.app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

if __name__ == "__main__":
    my_app = WebServer()
    my_app.run()

I tried to use gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 WebServer:my_app to run the server, but I got the error:

2023-04-10 01:41:27 Failed to find attribute 'my_app' in 'WebServer'.
2023-04-10 01:41:27 [2023-04-10 05:41:27 +0000] [6] [INFO] Worker exiting (pid: 6)
2023-04-10 01:41:27 [2023-04-10 05:41:27 +0000] [1] [INFO] Shutting down: Master
2023-04-10 01:41:27 [2023-04-10 05:41:27 +0000] [1] [INFO] Reason: App failed to load.

May I ask for the right command to run this Flask server which is wrapped in a Class with gunicorn?

Thanks!


Solution

  • This isn't working because gunicorn expects an object of your Flask application. Your my_app.run() return None which will not work with gunicorn. Another method for you is to modify the run method to return an self.app without giving the host or port as Gunicorn will take care of that. The creation should then take place through an explicit method call. This is how you can go about it:

    class WebServer:
    
        def __init__(self):
            self.app = Flask(__name__)
            self.generateURL()
           
        def generateURL(self):
            self.app.route("/")(self.test)
            self.app.route('/weight', methods=['GET'])(self.receive_weight)
            self.app.route('/usage', methods=['GET'])(self.receive_usage)
    
       ... 
        def run(self):
            return self.app
    
    def create_app():
        my_app = WebServer()
        return my_app.run()
    

    To run the above app use the command, assuming your file's name is 'WebServer.py`:

    gunicorn --bind=0.0.0.0:8080 --workers 1 --threads 8 --timeout 0 "WebServer:create_app()"