Skip to main content

WSGI server implemented in Rust.

Project description

Pyruvate WSGI server

https://gitlab.com/tschorr/pyruvate/badges/master/pipeline.svg https://codecov.io/gl/tschorr/pyruvate/branch/master/graph/badge.svg http://img.shields.io/pypi/v/pyruvate.svg

Pyruvate is a reasonably fast, multithreaded, non-blocking WSGI server implemented in Rust.

Features

Installation

If you are on Linux and use a recent Python version,

$ pip install pyruvate

is probably all you need to do.

Manylinux2010 binary wheels

Manylinux2010 wheels are available for active Python 3 versions (currently 3.6-3.10). Pip supports manylinux2010 wheels since version 19.0. Setuptools (used by e.g. zc.buildout) supports manylinux2010 wheels since version 42.0.0. So if you are on Linux and the Pyruvate source distribution is preferred over the binary package try upgrading pip and/or setuptools first.

Source installation

On macOS or if for any other reason you want to install the source tarball (e.g. using pip install –no-binary) you will need to install Rust first.

Development Installation

  • Install Rust

  • Install and activate a Python 3 (>= 3.6) 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 32 headers

async_logging

Optional: Log asynchronously using a dedicated thread. Defaults to True.

max_reuse_count

Optional: Specify how often to reuse an existing connection. Setting this parameter to 0 will effectively disable keep-alive connections. This is the default.

keepalive_timeout

Optional: Specify a timeout in integer seconds for keepalive connection. The persistent connection will be closed after the timeout expires. Defaults to 60 seconds.

chunked_transfer

Optional: Whether to use chunked transfer encoding if no Content-Length header is present. Defaults to False.

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

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 3.2.x, 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):

import os.path
import pyruvate

from mapproxy.wsgiapp import make_wsgi_app
application = make_wsgi_app(r'/path/to/mapproxy/mapproxy.yaml')

pyruvate.serve(application, "127.0.0.1:8005", 2)

Start from your virtualenv:

$ python config.py

Tested with Mapproxy 1.13.x, 1.12.x.

Plone

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

There is a minimal buildout example configuration for Plone 5.2 in the examples directory of the package.

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 2.0, 1.10.x.

Radicale

You can find an example configuration for Radicale in the examples directory of the package. Tested with Radicale 3.0.

Nginx settings

Like other WSGI servers Pyruvate should be used behind a reverse proxy, e.g. Nginx:

....
location / {
    proxy_pass http://localhost:7878;
    ...
}
...

Nginx doesn’t use keepalive connections by default so you will need to modify your configuration if you want persistent connections.

Changelog

1.1.3 (2022-04-11)

  • Simplify response writing and improve performance (#12)

  • Improve signal handling (#13)

1.1.2 (2022-01-10)

  • Migrate to Rust 2021

  • Use codecov binary uploader

  • Add CONTRIBUTING.rst

  • Fixed: The wrk benchmarking tool could make pyruvate hang when there is no Content-Length header (#11)

1.1.1 (2021-10-12)

  • Support Python 3.10

1.1.0 (2021-09-14)

  • Refactor FileWrapper and improve its performance

  • Increase the default maximum number of headers

  • Add Radicale example configuration

  • Update development status

1.0.3 (2021-06-05)

  • HEAD request: Do not complain about content length mismatch (#4)

  • More appropriate log level for client side connection termination (#5)

  • Simplify request parsing

1.0.2 (2021-05-02)

  • Close connection and log an error in the case where the actual content length is less than the Content-Length header provided by the application

  • Fix readme

1.0.1 (2021-04-28)

  • Fix decoding of URLs that contain non-ascii characters

  • Raise Python exception when response contains objects other than bytestrings instead of simply logging the error.

1.0.0 (2021-03-24)

  • Improve query string handling

0.9.2 (2021-01-30)

  • Better support for HTTP 1.1 Expect/Continue

  • Improve documentation

0.9.1 (2021-01-13)

  • Improve GIL handling

  • Propagate worker thread name to Python logging

  • Do not report broken pipe as error

  • PasteDeploy entry point: fix option handling

0.9.0 (2021-01-06)

  • Reusable connections

  • Chunked transfer-encoding

  • Support macOS

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

pyruvate-1.1.3.tar.gz (67.7 kB view details)

Uploaded Source

Built Distributions

pyruvate-1.1.3-cp310-cp310-manylinux2010_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.12+ x86-64

pyruvate-1.1.3-cp39-cp39-manylinux2010_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.12+ x86-64

pyruvate-1.1.3-cp38-cp38-manylinux2010_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.12+ x86-64

pyruvate-1.1.3-cp37-cp37m-manylinux2010_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.7m manylinux: glibc 2.12+ x86-64

pyruvate-1.1.3-cp36-cp36m-manylinux2010_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.6m manylinux: glibc 2.12+ x86-64

File details

Details for the file pyruvate-1.1.3.tar.gz.

File metadata

  • Download URL: pyruvate-1.1.3.tar.gz
  • Upload date:
  • Size: 67.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for pyruvate-1.1.3.tar.gz
Algorithm Hash digest
SHA256 c429860823c10318791554885cff02a8466613def0823432b0f505838ae153e8
MD5 a205c2f37808df7f83fbe523484eedc4
BLAKE2b-256 fca20a78173df404315978b0066d15b98aeb84b3c3d9b2009238190eb8db1448

See more details on using hashes here.

File details

Details for the file pyruvate-1.1.3-cp310-cp310-manylinux2010_x86_64.whl.

File metadata

  • Download URL: pyruvate-1.1.3-cp310-cp310-manylinux2010_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.10, manylinux: glibc 2.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for pyruvate-1.1.3-cp310-cp310-manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 a4063ab0061b8fba7f4acb7a1c23ddb72401e68f4aa81256f070072f88cf964e
MD5 11232a07d2fa068b39168acc897425f2
BLAKE2b-256 44cd380440efa961d9d87bf14d40c3c9b9047f9ed34ea3a4b09b91ab1953cb00

See more details on using hashes here.

File details

Details for the file pyruvate-1.1.3-cp39-cp39-manylinux2010_x86_64.whl.

File metadata

  • Download URL: pyruvate-1.1.3-cp39-cp39-manylinux2010_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.9, manylinux: glibc 2.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for pyruvate-1.1.3-cp39-cp39-manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 d3219b1d67e39198f52fbee8cac20f574bf23274f75a77cb85b995334723236c
MD5 8a59d7e35bc1fa50aea0bdae6a162fe9
BLAKE2b-256 359d6d2a107a33174cb781f0cb855cb6b1c5559b6f42f88d78bea8f4c7732fb2

See more details on using hashes here.

File details

Details for the file pyruvate-1.1.3-cp38-cp38-manylinux2010_x86_64.whl.

File metadata

  • Download URL: pyruvate-1.1.3-cp38-cp38-manylinux2010_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.8, manylinux: glibc 2.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for pyruvate-1.1.3-cp38-cp38-manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 6f58df2af6f20afe9809767245ff54063903d9faf19eb2f418ab4eaaf5b9eea0
MD5 2dac765b2ad58912b1097586bf0d564e
BLAKE2b-256 e90789eeefc02afce050742a221dfca25aa0b6f46ccdfa96873ca32e6f819115

See more details on using hashes here.

File details

Details for the file pyruvate-1.1.3-cp37-cp37m-manylinux2010_x86_64.whl.

File metadata

  • Download URL: pyruvate-1.1.3-cp37-cp37m-manylinux2010_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.7m, manylinux: glibc 2.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for pyruvate-1.1.3-cp37-cp37m-manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 eed8054dce5034fa350827de59fc7c6a716aae208d2cd475f20e9a7d2849211d
MD5 bb4d250c74de098b549378dbb925d826
BLAKE2b-256 c08516b1965fd137025c52888cef07fb1a406e100aac3842557890e39bda3a75

See more details on using hashes here.

File details

Details for the file pyruvate-1.1.3-cp36-cp36m-manylinux2010_x86_64.whl.

File metadata

  • Download URL: pyruvate-1.1.3-cp36-cp36m-manylinux2010_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.6m, manylinux: glibc 2.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for pyruvate-1.1.3-cp36-cp36m-manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 81124e73be577b0c3d94876159591873827307ef3f882faecb7e5e62be8e3d5d
MD5 b8145e4a0479d8fc66e1e3cbabb4e240
BLAKE2b-256 8225420378b8de6fb3a19f82cdfa62ea805b83aea057bb30f0b867a394b140d7

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page