Can I serve multiple clients using just Flask app.run() as standalone?
Asked Answered
R

3

255

I know I can link Flask with Apache or other web servers. But, I was thinking of running Flask as a standalone server serving multiple clients simultaneously.

Is this possible? Do I have to handle spawning multiple threads and managing them?

Redding answered 11/2, 2013 at 14:34 Comment(0)
S
363

flask.Flask.run accepts additional keyword arguments (**options) that it forwards to werkzeug.serving.run_simple - two of those arguments are threaded (a boolean) and processes (which you can set to a number greater than one to have werkzeug spawn more than one process to handle requests).

threaded defaults to True as of Flask 1.0, so for the latest versions of Flask, the default development server will be able to serve multiple clients simultaneously by default. For older versions of Flask, you can explicitly pass threaded=True to enable this behaviour.

For example, you can do

if __name__ == '__main__':
    app.run(threaded=True)

to handle multiple clients using threads in a way compatible with old Flask versions, or

if __name__ == '__main__':
    app.run(threaded=False, processes=3)

to tell Werkzeug to spawn three processes to handle incoming requests, or just

if __name__ == '__main__':
    app.run()

to handle multiple clients using threads if you know that you will be using Flask 1.0 or later.

That being said, Werkzeug's serving.run_simple wraps the standard library's wsgiref package - and that package contains a reference implementation of WSGI, not a production-ready web server. If you are going to use Flask in production (assuming that "production" is not a low-traffic internal application with no more than 10 concurrent users) make sure to stand it up behind a real web server (see the section of Flask's docs entitled Deployment Options for some suggested methods).

Sighted answered 12/2, 2013 at 1:20 Comment(12)
What if I am looking at a max of 100 users? Can I just assign processes=100 and be happy with it? In my case, I only need static files, no HTTP Post methods. My requirement is, I want to run all Flask threads as part of my parent app, so that they all can share variables.Redding
Chuckles - @Redding - no, that would probably be quite counter-productive (Processes are relatively expensive, and unless you are doing a lot of work in each request there is no reason why 4 or 8 processes shouldn't be enough). That said, if you are only displaying static content you would be better off with a server that is optimized for doing that (Apache, ngnix, IIS).Sighted
Also, you shouldn't commonly need to share variables across requests - if you do you'll either need to limit yourself to one process or use some out-of-band communication (Redis, a database, the filesystem, etc.) so that each of your processes stays synced.Sighted
Yeah right. So, if I set processes=4, then it should spawn 100 threads as per my need, won't it?Redding
@Redding - are you planning on having 100 concurrent users or 100 users total? It most likely will not spawn 100 threads, it will spawn some lower number and handle the connections as they come in - you don't need a 1 to 1 match between incoming connections and handlers - but as the number of concurrent incoming connections goes up you either need to increase the number of handlers (which is counter-productive after a certain number) or decrease your handling time. If you are planning on 100 concurrent users you'll probably want a vetted webserver, rather than wsgiref.Sighted
OK, so if I will only ever have 100 users total, then can I just have Flask without any other components?Redding
@Redding - if you can't spin up a better server then I'd just give it a whirl and see what happens. If it doesn't perform well under load you can deploy it behind a different webserver.Sighted
@ATOzTOA, regarding your question about why you can't specify 'threaded' and 'processes' at the same time, cf the code here: werkzeug.readthedocs.org/en/latest/_modules/werkzeug/servingDozier
Does using N processes run N concurrent applications? If I use globals to be shared by different views within the app, they only share properly if processes is 1. I expect each of the N processes to have its own copy of the globals to share among its views, but not between the processes. Even globals within a process are unusable if processes>1. Will flask.g properly share globals if multithreaed=True or processes=N for N>1?Photocopy
Is it possible to specify processes=N when running a Flask app as a package form the command line?Cayser
Not when last I checked @Cayser - but that may have changed.Sighted
For the ones who is looking to know how is the full solution using Docker, can see this post.Swanger
Q
72

Using the simple app.run() from within Flask creates a single synchronous server on a single thread capable of serving only one client at a time. It is intended for use in controlled environments with low demand (i.e. development, debugging) for exactly this reason.

Spawning threads and managing them yourself is probably not going to get you very far either, because of the Python GIL.

That said, you do still have some good options. Gunicorn is a solid, easy-to-use WSGI server that will let you spawn multiple workers (separate processes, so no GIL worries), and even comes with asynchronous workers that will speed up your app (and make it more secure) with little to no work on your part (especially with Flask).

Still, even Gunicorn should probably not be directly publicly exposed. In production, it should be used behind a more robust HTTP server; nginx tends to go well with Gunicorn and Flask.

Qktp answered 11/2, 2013 at 16:3 Comment(3)
not quite. Gunicorn is python, nginx is not. that's not how you would use them, though. Gunicorn would let you run your app as gunicorn app:app 127.0.0.1:8080 instead of python app.py. Nginx would act as the public service that exposes your private Gunicorn-run app (a reverse-proxy), hiding all sorts of lower level HTTP implementation details, perhaps serving static files directly, etc.Qktp
Flask with app.run(threaded=True) runs very nice on Apache2 using mod_wsgi flask.palletsprojects.com/en/1.1.x/deploying/mod_wsgiMaxey
Where does Apache fit in this picture? I have shared hosting where I must use it. I'm recreating the environment on a VPS to get the hands on. ThanksTasteless
F
25

Tips from 2020:

From Flask 1.0, it defaults to enable multiple threads (source), you don't need to do anything, just upgrade it with:

$ pip install -U flask

If you are using flask run instead of app.run() with older versions, you can control the threaded behavior with a command option (--with-threads/--without-threads):

$ flask run --with-threads

It's same as app.run(threaded=True)

Felisha answered 16/9, 2020 at 0:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.