WSGI server implemented in Rust.
Reason this release was yanked:
outdated release - please use the latest version
Project description
Pyruvate WSGI server
Pyruvate is a reasonably fast, multithreaded, non-blocking WSGI server implemented in Rust.
Features
Non-blocking read/write using mio
Request parsing using httparse
rust-cpython based Python interface
Worker pool based on threadpool
PasteDeploy entry point
Development Installation
Install Rust
Install and activate a Python 3 (> 3.5) virtualenv
Install setuptools_rust using pip:
$ pip install setuptools_rust
Install pyruvate, e.g. using pip:
$ pip install -e git+https://gitlab.com/tschorr/pyruvate.git#egg=pyruvate[test]
Using Pyruvate in your WSGI application
From Python
A hello world WSGI application using pyruvate listening on 127.0.0.1:7878 and using 2 worker threads looks like this:
import pyruvate def application(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers, None) return [b"Hello world!\n"] pyruvate.serve(application, "127.0.0.1:7878", 2)
Using PasteDeploy
Again listening on 127.0.0.1:7878 and using 2 worker threads:
[server:main] use = egg:pyruvate#main socket = 127.0.0.1:7878 workers = 2
Configuration Options
- socket
Required: The TCP socket Pyruvate should bind to. pyruvate also supports systemd socket activation If you specify None as the socket value, pyruvate will try to acquire a socket bound by systemd.
- workers
Required: Number of worker threads to use.
- write_blocking
Optional: Use a blocking connection for writing. Pyruvate currently supports two types of workers: The default worker will write in a non-blocking manner, registering WSGI responses for later processing if the socket isn’t available for writing immediately. By setting this option to True you can enable a worker that will instead set the connection into blocking mode for writing. Defaults to False.
- max_number_headers
Optional: Maximum number of request headers that will be parsed. If a request contains more headers than configured, request processing will stop with an error indicating an incomplete request. The default is 24 headers
- async_logging
Optional: Log asynchronously using a dedicated thread. Defaults to True.
Logging
Pyruvate uses the standard Python logging facility. The logger name is pyruvate. See the Python documentation (logging, logging.config) for configuration options.
Example Configurations
Django 2
After installing Pyruvate in your Django virtualenv, create or modify your wsgi.py file (one worker listening on 127.0.0.1:8000):
import os import pyruvate from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_django_application.settings") application = get_wsgi_application() pyruvate.serve(application, "127.0.0.1:8000", 1)
You can now start Django + Pyruvate with:
$ python wsgi.py
Override settings by using the DJANGO_SETTINGS_MODULE environment variable when appropriate. Tested with Django 2.2.x.
MapProxy
First create a basic WSGI configuration following the MapProxy deployment documentation. Then modify config.py so it is using Pyruvate (2 workers listening on 127.0.0.1:8005):
from logging.config import fileConfig import os.path import pyruvate fileConfig(r'/path/to/mapproxy/log.ini', {'here': os.path.dirname(__file__)}) from mapproxy.wsgiapp import make_wsgi_app application = make_wsgi_app(r'/path/to/mapproxy/mapproxy.yml') pyruvate.serve(application, "127.0.0.1:8005", 2)
Start from your virtualenv:
$ python config.py
Tested with Mapproxy 1.12.x.
Plone 5.2
Using zc.buildout and plone.recipe.zope2instance you can define an instance part using Pyruvate’s PasteDeploy <https://pastedeploy.readthedocs.io/en/latest/> _entry point:
[instance] recipe = plone.recipe.zope2instance http-address = 127.0.0.1:8080 eggs = Plone pyruvate wsgi-ini-template = ${buildout:directory}/templates/pyruvate.ini.in
The server section of the template provided with the wsgi-ini-template option should look like this (3 workers listening on http-address as specified in the buildout [instance] part):
[server:main] use = egg:pyruvate#main socket = %(http_address)s workers = 3
Tested with Plone 5.2.x.
Pyramid
Install Pyruvate in your Pyramid virtualenv using pip:
$ pip install pyruvate
Modify the server section in your .ini file to use Pyruvate’s PasteDeploy <https://pastedeploy.readthedocs.io/en/latest/> _entry point (listening on 127.0.0.1:7878 and using 5 workers):
[server:main] use = egg:pyruvate#main socket = 127.0.0.1:7878 workers = 5
Start your application as usual using pserve:
$ pserve path/to/your/configfile.ini
Tested with Pyramid 1.10.x.
Nginx settings
Like other WSGI servers pyruvate should be used behind a reverse proxy, e.g. Nginx:
.... location / { proxy_pass http://localhost:7878; ... } ...
Changelog
0.8.4 (2020-12-12)
lower CPU usage
0.8.3 (2020-11-26)
clean wheel build directories
fix some test isolation problems
remove a println
0.8.2 (2020-11-17)
Fix blocksize handling for sendfile case
Format unix stream peer address
Use latest mio
0.8.1 (2020-11-10)
Receiver in non-blocking worker must not block when channel is empty
0.8.0 (2020-11-07)
Logging overhaul
New async_logging option
Some performance improvements
Support Python 3.9
Switch to manylinux2010 platform tag
0.7.1 (2020-09-16)
Raise Python exception when socket is unavailable
Add Pyramid configuration example in readme
0.7.0 (2020-08-30)
Use Python logging
Display server info on startup
Fix socket activation for unix domain sockets
0.6.2 (2020-08-12)
Improved logging
PasteDeploy entry point now also uses at most 24 headers by default
0.6.1 (2020-08-10)
Improve request parsing
Increase default maximum number of headers to 24
0.6.0 (2020-07-29)
Support unix domain sockets
Improve sendfile usage
0.5.3 (2020-07-15)
Fix testing for completed sendfile call in case of EAGAIN
0.5.2 (2020-07-15)
Fix testing for completed response in case of EAGAIN
Cargo update
0.5.1 (2020-07-07)
Fix handling of read events
Fix changelog
Cargo update
‘Interrupted’ error is not a todo
Remove unused code
0.5.0 (2020-06-07)
Add support for systemd socket activation
0.4.0 (2020-06-29)
Add a new worker that does nonblocking write
Add default arguments
Add option to configure maximum number of request headers
Add Via header
0.3.0 (2020-06-16)
Switch to rust-cpython
Fix passing of tcp connections to worker threads
0.2.0 (2020-03-10)
Added some Python tests (using py.test and tox)
Improve handling of HTTP headers
Respect content length header when using sendfile
0.1.0 (2020-02-10)
Initial release
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for pyruvate-0.8.4-cp39-cp39-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 12d35e213f61e83c4a46c0e1e51231e6524af1e36cde8e86e9084d29b266c157 |
|
MD5 | c668a3f2ce78cc6c72dc843da0e64d7c |
|
BLAKE2b-256 | 22b7d0f51fdafa429379d6ff0eea87f427f3a402f85b52a1f7df028301f3eed3 |
Hashes for pyruvate-0.8.4-cp38-cp38-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 34acc7660596c421851d9c5d12b1a2475d53457528a32ca1730297ab17b6e72d |
|
MD5 | 114e5ac71f37e4cc7ba22d196f55ce48 |
|
BLAKE2b-256 | 6722fd23740efa6896d06272b0983d4cfdd7b20fd2295b9c58f348c8a33bff90 |
Hashes for pyruvate-0.8.4-cp37-cp37m-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dc6d6dddd90edb32e0f6eefd421e4b39425374cac6524d122030858f7dea0f11 |
|
MD5 | 0bdc43298e83ff04f9ee46605ad77cf1 |
|
BLAKE2b-256 | 5031d06f5cac9426db8c42548800f8dfc3bb018358343f3fd1b884ea93fe8eae |
Hashes for pyruvate-0.8.4-cp36-cp36m-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3bfdaa45363e4eed802c64f65de6bf433d42ac5e6866a218f7ce5d1e84364cdc |
|
MD5 | 7a96b390fd4cc997c3be6e8f060f110c |
|
BLAKE2b-256 | 129c08596543a9f88ff97129676c21e63cd59baefdf24a349096e3eaa6855565 |