How does WSGI work?

Visto 119 veces
Saltar al primer mensaje no leído

Tal

no leída,
26 feb 2019, 13:26:4326/2/19
a Django users
I've been developing web applications using Flask and Django for about a year now, and although I've come across the term WSGI a bunch of times in both frameworks, I never really understood what it did. I'm sure I'm not the only one. The quick explanations I read never made sense to me. Even PEP3333 didn't really give me a clear picture of how WSGI fits in with Nginx, and Django. There are a bunch of articles online that quickly show how to setup nginx, gunicorn/uwsgi and django to work in production, and once I figured that out, I never really had a reason to figure out WSGI again. But it's been a year now, and I probably should understand at least the basics.

I did a bit more reading recently, and I think I get it. Just looking for someone to confirm that I'm on the right track.
This is how I think it works:

My example uses the most common setup I use: Nginx, Gunicorn and Django
  • When an HTTP request comes in, it hits Nginx first
    • Nginx runs multiple processes, and makes sure that browsers/clients that have a slow connection don't effect other clients
    • If it's a request for a static file, like a CSS file, JS, image, or anything like that, Nginx returns it directly
    • If it's a request for anything else, it uses HTTP to send the request over a Unix socket to Gunicorn
      • Doesn't have to be a Unix socket, but if both Nginx and Gunicorn are running on the same host, it makes sense to use Unix sockets
      • The main point is that Nginx uses HTTP to communicate with Gunicorn
  • Gunicorn
    • Starts up x worker processes on startup (as many as you tell it)
    • Each worker process imports your application's code (django.core.wsgi.get_wsgi_application() in Django's case)
      • The application's code is a callable function
      • Gunicorn imports it so that it's ready to make a function call to it as soon as an HTTP request comes in
    • When an HTTP request comes in from Nginx, Gunicorn will:
      • Use its main process to assign the request to a free worker process
      • The worker process translates the HTTP headers into a python dictionary (commonly called the 'environment' dictionary)
      • The worker process makes a function call to your application, passing it the 'environment' dictionary, and a start_response function
  • When your application (Django) decides what to do about the request, and decides to formulate a response, it will:
    • Call start_response, giving it the HTTP response status (eg. 200 OK), and the HTTP response headers as a Python object (list of tuples)
      • Note: At this point, nothing is sent to the client's browser, or even Nginx yet
    • Return the body of the response as an iterable
  • Gunicorn will then:
    • Add any required HTTP headers the application didn't provide
    • Turn the status, headers and body that it received from the application into an HTTP response message
    • Send the response back to Nginx using HTTP
  • Nginx will then send the response back to the client

So the job of the individual parts is basically this:
  1. Nginx
    • Buffers slow clients
    • Quickly serves static files
    • Possibly handle SSL, if configured
    • Passes HTTP requests to Gunicorn (also using HTTP)
  2. Gunicorn
    • Deals with TCP connections between nginx and itself
      • Prevents your application from needing to do lower-level socket stuff with TCP
    • Converts HTTP requests into Python objects, and responses back into HTTP
  3. Django
    • Just worries about formulating responses to requests, not keeping track of TCP connections, or HTTP, or anything low-level

For Apache, they have mod_wsgi, which takes the place of Gunicorn, acting as a WSGI server.

That sound right? Or am I way off?

Motaz Hejaze

no leída,
26 feb 2019, 14:28:2626/2/19
a django...@googlegroups.com
You are very close to what realy happens , most of devs know nothing aboutbthis stuff

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/77576c51-8237-46b1-bd48-8f30bbaea3bf%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tal

no leída,
26 feb 2019, 14:39:0026/2/19
a Django users
Did I get something wrong?
Do you mean the devs working on the Django project know nothing about this, or the devs using Django to build web apps?
From what I've read, devs using Django don't need to be too familiar with WSGI, but it seems like it helps at least having a conceptual understanding of what it is.

m1chael

no leída,
26 feb 2019, 16:49:0326/2/19
a django...@googlegroups.com

Tal

no leída,
26 feb 2019, 17:13:0026/2/19
a Django users
Is it right though?

Tal

no leída,
7 mar 2019, 18:11:147/3/19
a Django users
The word "simple" appears 13 times in PEP3333, but no one knows how this magical specification works?
Can anyone confirm I'm not crazy please?

Mike Dewhirst

no leída,
7 mar 2019, 19:00:087/3/19
a Django users
On 8/03/2019 10:11 am, Tal wrote:
> The word "simple" appears 13 times in PEP3333, but no one knows how
> this magical specification works?
> Can anyone confirm I'm not crazy please?

You could try writing to Grahame Dumpleton for confirmation. I'm
reasonably sure he wrote mod_wsgi and ought to be able to correct you if
you've misunderstood anything.He used to give presentations on wsgi at
PyCons so you might be able to find something on YouTube from a few
years ago.

Last I heard of him he is fairly focused on Kubernetes so he probably
doesn't monitor the Django list any more.
> * When an HTTP request comes in, it hits Nginx first
> o Nginx runs multiple processes, and makes
> sure that browsers/clients that have a
> slow connection don't effect other clients
> o If it's a request for a static file, like
> a CSS file, JS, image, or anything like
> that, Nginx returns it directly
> o If it's a request for anything else, it
> uses *HTTP* to send the request over a
> Unix socket to Gunicorn
> + Doesn't have to be a Unix socket, but
> if both Nginx and Gunicorn are running
> on the same host, it makes sense to
> use Unix sockets
> + The main point is that Nginx uses HTTP
> to communicate with Gunicorn
> * Gunicorn
> o Starts up x worker processes on startup
> (as many as you tell it)
> o Each worker process imports your
> application's code
> (django.core.wsgi.get_wsgi_application()
> in Django's case)
> + The application's code is a callable
> function
> + Gunicorn imports it so that it's ready
> to make a function call to it as soon
> as an HTTP request comes in
> o When an HTTP request comes in from Nginx,
> Gunicorn will:
> + Use its main process to assign the
> request to a free worker process
> + The worker process translates the HTTP
> headers into a python dictionary
> (commonly called the 'environment'
> dictionary)
> + The worker process makes a function
> call to your application, passing it
> the 'environment' dictionary, and a
> start_response function
> * When your application (Django) decides what to
> do about the request, and decides to formulate
> a response, it will:
> o Call start_response, giving it the HTTP
> response status (eg. 200 OK), and the HTTP
> response headers as a Python object (list
> of tuples)
> + Note: At this point, nothing is sent
> to the client's browser, or even Nginx yet
> o *Return* the body of the response as an
> iterable
> * Gunicorn will then:
> o Add any required HTTP headers the
> application didn't provide
> o Turn the status, headers and body that it
> received from the application into an HTTP
> response message
> o Send the response back to Nginx using HTTP
> * Nginx will then send the response back to the
> client
>
>
> So the job of the individual parts is basically this:
>
> 1. Nginx
> * Buffers slow clients
> * Quickly serves static files
> * Possibly handle SSL, if configured
> * Passes HTTP requests to Gunicorn (also
> using HTTP)
> 2. Gunicorn
> * Deals with TCP connections between nginx
> and itself
> o Prevents your application from needing
> to do lower-level socket stuff with TCP
> * Converts HTTP requests into Python
> objects, and responses back into HTTP
> 3. Django
> * Just worries about formulating responses
> to requests, not keeping track of TCP
> connections, or HTTP, or anything low-level
>
>
> For Apache, they have mod_wsgi, which takes the
> place of Gunicorn, acting as a WSGI server.
>
> That sound right? Or am I way off?
> --
> You received this message because you are
> subscribed to the Google Groups "Django users" group.
> To unsubscribe from this group and stop receiving
> emails from it, send an email to
> django-users...@googlegroups.com.
> To post to this group, send email to
> django...@googlegroups.com.
> Visit this group at
> https://groups.google.com/group/django-users
> <https://groups.google.com/group/django-users>.
> <https://groups.google.com/d/msgid/django-users/77576c51-8237-46b1-bd48-8f30bbaea3bf%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit
> https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
> --
> You received this message because you are subscribed to
> the Google Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails
> from it, send an email to django-users...@googlegroups.com.
> To post to this group, send email to
> django...@googlegroups.com.
> Visit this group at
> https://groups.google.com/group/django-users
> <https://groups.google.com/group/django-users>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/f25e3afa-64dc-4d3e-b546-e0352cfcd5d1%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/f25e3afa-64dc-4d3e-b546-e0352cfcd5d1%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/a16dad62-5864-4a20-bc89-24d70f68a37c%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/a16dad62-5864-4a20-bc89-24d70f68a37c%40googlegroups.com?utm_medium=email&utm_source=footer>.

Joel Mathew

no leída,
7 mar 2019, 19:54:477/3/19
a django...@googlegroups.com
There's a mod_wsgi_express thread that Graham monitors, so he's sure to get feedback from there 

Understanding this better could help me solve static file blues. Most of the time I don't understand why my static files fine aren't served when I move to production.

Mike Dewhirst

no leída,
7 mar 2019, 20:41:397/3/19
a django...@googlegroups.com
On 8/03/2019 11:54 am, Joel Mathew wrote:
> There's a mod_wsgi_express thread that Graham monitors, so he's sure
> to get feedback from there
>
> Understanding this better could help me solve static file blues. Most
> of the time I don't understand why my static files fine aren't served
> when I move to production.

Usually it is because they are in the wrong place.

Your production webserver (in my case Apache) probably wants to serve
the static files directly without Django getting involved at all. There
should be an alias directive in your webserver conf which specifies the
actual location of your static files base directory and equates that
with the STATIC_URL value in your settings. Similarly for the MEDIA_URL
value.

All you really need to do is write a script to copy your static files
from where they live in your dev environment to the location specified
by STATIC_URL in your production environment.

Alternatively, manage.py collectstatic will do that for you.

>
> On Fri, 8 Mar, 2019, 5:29 AM Mike Dewhirst, <mi...@dewhirst.com.au
> <mailto:mi...@dewhirst.com.au>> wrote:
>
> On 8/03/2019 10:11 am, Tal wrote:
> > The word "simple" appears 13 times in PEP3333, but no one knows how
> > this magical specification works?
> > Can anyone confirm I'm not crazy please?
>
> You could try writing to Grahame Dumpleton for confirmation. I'm
> reasonably sure he wrote mod_wsgi and ought to be able to correct
> you if
> you've misunderstood anything.He used to give presentations on
> wsgi at
> PyCons so you might be able to find something on YouTube from a few
> years ago.
>
> Last I heard of him he is fairly focused on Kubernetes so he probably
> doesn't monitor the Django list any more.
>
> >
> > On Tuesday, February 26, 2019 at 3:13:00 PM UTC-7, Tal wrote:
> >
> >     Is it right though?
> >
> >     On Tuesday, February 26, 2019 at 2:49:03 PM UTC-7, mike wrote:
> >
> >         Great write up!
> >
> >         On Tue, Feb 26, 2019 at 2:39 PM Tal <tal....@gmail.com
> <mailto:tal....@gmail.com>> wrote:
> >
> >             Did I get something wrong?
> >             Do you mean the devs working on the Django project know
> >             nothing about this, or the devs using Django to
> build web
> >             apps?
> >             From what I've read, devs using Django don't need to be
> >             too familiar with WSGI, but it seems like it helps at
> >             least having a conceptual understanding of what it is.
> >
> >             On Tuesday, February 26, 2019 at 12:28:26 PM UTC-7,
> Motaz
> >             Hejaze wrote:
> >
> >                 You are very close to what realy happens , most of
> >                 devs know nothing aboutbthis stuff
> >
> >                 On Tue, 26 Feb 2019, 20:26 Tal,
> > django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> >                     To post to this group, send email to
> > django...@googlegroups.com <mailto:django...@googlegroups.com>.
> >                     Visit this group at
> > https://groups.google.com/group/django-users
> >                     <https://groups.google.com/group/django-users>.
> >                     To view this discussion on the web visit
> >
> https://groups.google.com/d/msgid/django-users/77576c51-8237-46b1-bd48-8f30bbaea3bf%40googlegroups.com
> >                   
>  <https://groups.google.com/d/msgid/django-users/77576c51-8237-46b1-bd48-8f30bbaea3bf%40googlegroups.com?utm_medium=email&utm_source=footer>.
> >                     For more options, visit
> > https://groups.google.com/d/optout
> >                     <https://groups.google.com/d/optout>.
> >
> >             --
> >             You received this message because you are subscribed to
> >             the Google Groups "Django users" group.
> >             To unsubscribe from this group and stop receiving emails
> >             from it, send an email to
> django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> >             To post to this group, send email to
> > django...@googlegroups.com <mailto:django...@googlegroups.com>.
> >             Visit this group at
> > https://groups.google.com/group/django-users
> >             <https://groups.google.com/group/django-users>.
> >             To view this discussion on the web visit
> >
> https://groups.google.com/d/msgid/django-users/f25e3afa-64dc-4d3e-b546-e0352cfcd5d1%40googlegroups.com
> >           
>  <https://groups.google.com/d/msgid/django-users/f25e3afa-64dc-4d3e-b546-e0352cfcd5d1%40googlegroups.com?utm_medium=email&utm_source=footer>.
> >             For more options, visit
> https://groups.google.com/d/optout
> >             <https://groups.google.com/d/optout>.
> >
> > --
> > You received this message because you are subscribed to the Google
> > Groups "Django users" group.
> > To unsubscribe from this group and stop receiving emails from
> it, send
> > an email to django-users...@googlegroups.com
> <mailto:django-users%2Bunsu...@googlegroups.com>
> > <mailto:django-users...@googlegroups.com
> <mailto:django-users%2Bunsu...@googlegroups.com>>.
> > To post to this group, send email to
> django...@googlegroups.com <mailto:django...@googlegroups.com>
> > <mailto:django...@googlegroups.com
> <mailto:django...@googlegroups.com>>.
> > Visit this group at https://groups.google.com/group/django-users.
> > To view this discussion on the web visit
> >
> https://groups.google.com/d/msgid/django-users/a16dad62-5864-4a20-bc89-24d70f68a37c%40googlegroups.com
>
> >
> <https://groups.google.com/d/msgid/django-users/a16dad62-5864-4a20-bc89-24d70f68a37c%40googlegroups.com?utm_medium=email&utm_source=footer>.
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to django-users...@googlegroups.com
> <mailto:django-users%2Bunsu...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/CAA%3Diw_8kGTyC7w7niBYs%3DxLXhw%2BvRRABqPFntqRUfMK64nVqrQ%40mail.gmail.com
> <https://groups.google.com/d/msgid/django-users/CAA%3Diw_8kGTyC7w7niBYs%3DxLXhw%2BvRRABqPFntqRUfMK64nVqrQ%40mail.gmail.com?utm_medium=email&utm_source=footer>.

Tal

no leída,
8 mar 2019, 16:37:558/3/19
a Django users
Ok - maybe I'll try to get a hold of Grahame Dumpleton when I have some time.

Thanks guys

PS.

Python frameworks like Flask or Django are good at making decisions about what response to return for a given request, and returning it.
In most cases, that response is an HTML page, or json, or something similar.
If a request comes that requires you to return a file however, this is best done by your web server software (nginx, apache, etc).
It can do it way more efficiently.
In production, if you set everything up as recommended, the request initially hits your web server, which decides if the request should be sent to Django, or if a file should be returned directly.
That decision is usually easy to make for the web server because all static files (files that never change, like images) are all in the same directory.
When you are writing your django project, you'll probably have individual static directories for every app.
As Mike pointed out, the "./manage.py collectstatic" command will gather all these static files from all your apps into a single folder, so that
your web server can easily determine if it should return a static file from that folder, or send the request to django.

Scot Hacker

no leída,
9 mar 2019, 12:19:379/3/19
a Django users
Excellent summary - should be posted for posterity on a blog or something. I don't know enough about wsgi internals to add to this, but would have been nice to have this to read the first time I set up a server, back in the day. 

./s
Responder a todos
Responder al autor
Reenviar
0 mensajes nuevos