WSGI

We assume you are familiar with python Web Standard Gateway Interface (WSGI), if not you should read pep-3333 first.

Setting Up

All pulsar needs to set-up a WSGI server is the callable of your application. We start by creating a script, called managed.py which will be used to run your server:

from pulsar.apps import wsgi

def callable(environ, start_response):
    ...

if __name__ == '__main__':
    wsgi.WSGIServer(callable).start()

Multiple Process

When serving lots of requests, an asynchronous single-process server may not be enough. To add power, you can run the server using 2 or more process (workers):

python manage.py --workers 4

Multi-process servers are only available for:

  • Posix systems.
  • Windows running python 3.3 or above.

Check multi-process socket servers documentation for more information.

Blocking middleware

Pulsar is an asynchronous server, however, the callable which consume your application may not be.

Note

Most web-framework in the public domain are blocking by construction. This is OK as long as the WSGI callable consumes the request and return control to pulsar as fast as possible.

In order to facilitate the integration of blocking frameworks, pulsar ships with several WSGI utilities, including:

  • WsgiHandler for grouping several WSGI middleware together
  • wait_for_body_middleware() should be placed before any synchronous middleware which needs to process the body of the HTTP request (such as POST methods)
  • middleware_in_executor(), a wrapper to execute a blocking middleware in the executor (threading pool) of the actor serving the request.

A pulsar friendly WSGI handler for a callable can take the following form:

from pulsar.apps import wsgi

def callable(environ, start_response):
    ...

wsgi_handler = wsgi.WsgiHandler([wsgi.wait_for_body_middleware,
                                 wsgi.middleware_in_executor(callable)])

if __name__ == '__main__':
    wsgi.WSGIServer(wsgi_handler()).start()

To control the number of thread workers in the event loop executor, one uses the thread-workers option. For example, the following command:

python manage.py -w 4 --thread-workers 10

will run four process based actors, each with an executor with up to 10 threads.

Serving More than one application

You can serve as many applications, on different addresses, as you like. For example, our manage.py script could be:

from pulsar import arbiter
from pulsar.apps import wsgi

def callable1(environ, start_response):
    ...

def callable2(environ, start_response):
    ...


if __name__ == '__main__':
    wsgi.WSGIServer(callable1, name='wsgi1')
    wsgi.WSGIServer(callable2, name='wsgi2', bind=8070)
    arbiter().start()