Skip to main content

WSGI server implemented in Rust.

Project description

Pyruvate WSGI server

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

Pyruvate is a fast, multithreaded 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.

Binary Packages

manylinux_2_28 and musllinux_1_2 wheels are available for the x86_64 architecture and active Python 3 versions (currently 3.9-3.13).

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.9) 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 using a TCP port

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)

From Python using a Unix socket

A hello world WSGI application using Pyruvate listening on unix:/tmp/pyruvate.socket 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, "/tmp/pyruvate.socket", 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.

async_logging

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

chunked_transfer

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

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.

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

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.

qmon_warn_threshold

Optional: Warning threshold for the number of requests in the request queue. A warning will be logged if the number of queued requests reaches this value. The value must be a positive integer. The default is None which disables the queue monitor.

send_timeout

Optional: Time to wait for a client connection to become available for writing after EAGAIN, in seconds. Connections that do not receive data within this time are closed. The value must be a positive integer. The default is 60 seconds.

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 4.1.x, 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.15.x, 1.13.x, 1.12.x.

Plone

Using pip

After installing Pyruvate in your Plone virtualenv, change the server section in your zope.ini file (located in instance/etc if you are using mkwsgiinstance to create the instance):

[server:main]
use = egg:pyruvate#main
socket = localhost:7878
workers = 2
Using zc.buildout

Using zc.buildout and plone.recipe.zope2instance you can define an instance part using Pyruvate’s PasteDeploy 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 6.0.x, 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 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.1.8.

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.4.0rc1 (2024-11-11)

  • Switch to pyo3-ffi and a stripped-down version of rust-cpython

  • Passing ‘blocksize’ as keyword argument to FileWrapper is no longer possible

1.3.0 (2024-07-04)

  • Switch back to rust-cpython (#29)

1.3.0-rc1 (2023-12-28)

  • Replace rust-cpython with PyO3 (#28)

  • Add support for Python 3.12

  • Drop support for Python 3.7

1.2.2 (2023-07-02)

  • Document Unix Domain Socket usage (#27)

  • Provide legacy manylinux wheel names (#26)

1.2.1 (2022-12-22)

  • Track and remove unfinished responses that did not otherwise error (#23)

  • Build musllinux_1_1 wheels (#24)

1.2.0 (2022-10-26)

  • Support Python 3.11 and discontinue Python 3.6, switch to manylinux2014 for building wheels (#19)

  • Add a request queue monitor (#17)

  • Remove blocking worker (#18)

  • Improve parsing of Content-Length header (#20)

1.1.4 (2022-04-19)

  • Fix handling of empty list responses (#14)

  • Support hostnames in socket addresses (#15)

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.4.0rc1.tar.gz (98.6 kB view details)

Uploaded Source

Built Distributions

pyruvate-1.4.0rc1-cp313-cp313-musllinux_1_2_x86_64.whl (453.3 kB view details)

Uploaded CPython 3.13 musllinux: musl 1.2+ x86-64

pyruvate-1.4.0rc1-cp313-cp313-manylinux_2_28_x86_64.whl (457.1 kB view details)

Uploaded CPython 3.13 manylinux: glibc 2.28+ x86-64

pyruvate-1.4.0rc1-cp312-cp312-musllinux_1_2_x86_64.whl (453.3 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.2+ x86-64

pyruvate-1.4.0rc1-cp312-cp312-manylinux_2_28_x86_64.whl (457.1 kB view details)

Uploaded CPython 3.12 manylinux: glibc 2.28+ x86-64

pyruvate-1.4.0rc1-cp311-cp311-musllinux_1_2_x86_64.whl (452.7 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.2+ x86-64

pyruvate-1.4.0rc1-cp311-cp311-manylinux_2_28_x86_64.whl (455.7 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.28+ x86-64

pyruvate-1.4.0rc1-cp310-cp310-musllinux_1_2_x86_64.whl (452.7 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.2+ x86-64

pyruvate-1.4.0rc1-cp310-cp310-manylinux_2_28_x86_64.whl (455.5 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.28+ x86-64

pyruvate-1.4.0rc1-cp39-cp39-musllinux_1_2_x86_64.whl (452.7 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.2+ x86-64

pyruvate-1.4.0rc1-cp39-cp39-manylinux_2_28_x86_64.whl (455.6 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.28+ x86-64

File details

Details for the file pyruvate-1.4.0rc1.tar.gz.

File metadata

  • Download URL: pyruvate-1.4.0rc1.tar.gz
  • Upload date:
  • Size: 98.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for pyruvate-1.4.0rc1.tar.gz
Algorithm Hash digest
SHA256 64dced273f450d4b6590bd1b4df4a6dbb77ac7b9a34c246743e1ebb620ac78a7
MD5 55971f438cbadeaa487c88af66b31198
BLAKE2b-256 533e5dcdf5641ca181ccb91da79a9a8706a23516011f19019afd54542be69d33

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 78967feececea6aaeff9909e374858896f26426f473ee97cc11c41ab9e805df8
MD5 19276fd9337f32bcc93ee732f3971d1e
BLAKE2b-256 7aa3b305d98f310fdab911552593076c9be525dd7fc085a5921cf9f84776a46f

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp313-cp313-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp313-cp313-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 dd2f5c28499e4575c232a1e01e72817a6378f3bc8565ed2046e077869c818a7c
MD5 1939e64a52e8a12b452bbabab72b3b9f
BLAKE2b-256 c26e71243925cb66f9c848dd70dd77fb264f30407a9c7bec55f9a4bd01bb8080

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 e94e92106e8bd8a6d1c87455480027b357efa4b4a4894fad7c87a54c09e7be0f
MD5 f62f74fc698fb80cab379ffd1fd5327f
BLAKE2b-256 9a3af3fe047c50388e629f477a8a596ce4331ca6ed67e0402f4ba0bed41df399

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b57265f4e8f37e878ff91630e6e4134bd734fb5b10da2a57928c6b6ea21bdc39
MD5 a92e34dbd005e1238fed0125352bd6d6
BLAKE2b-256 43243ee9e0805cd9e71937b207d9527c460048064d1c889e7de2cacdc1a738d7

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 6dfc3c06c176bf9e02436761c0ae3695ad8692c4dfb6e3c7a5997668b9cc09ee
MD5 6566ee6a485be05d7724937e51c851dc
BLAKE2b-256 a3d56bf92878fd3b780b2a928f684b9511dfa87f5b74ba3785ecb8bbfc7056a8

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8a71a9f66d3ffbc0d87f72f749ca5000d6a59f4345b1e895d547e1283625d078
MD5 891daed9b325e9206aad9d23d8696e88
BLAKE2b-256 ec244e5cfe308e6b24e22b81851766361a695b500b1657ddf6353634cf1276e9

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 108927e475e4fa89f2a946301001559d65d32bd249d4ed8434c5443c35ebf3f3
MD5 7d8dc1657f2daa4319ba3f919ec5e78f
BLAKE2b-256 db31e255a970eb1d785d2369e3b8c5ccfae7b9d551d54c0a226c0302b24a3855

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b51ba9d511519d8c0cc564234291083f57fe7700e23e50bd746fa11b0282fda6
MD5 d90a194f64d415d05a70779d2aab6c02
BLAKE2b-256 06749d2d8fbfc5c99e5acc405a36bf66a215c8fac066c07be8011b58e4e8bfe4

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp39-cp39-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 2c02984de1e71c086b0f30453dabf0d3a645398b45f5517598294f0b7cf93c10
MD5 2e19a475aaecc293a4f4b6b4c1e7f021
BLAKE2b-256 aca9e28db8fe2754311b78e8a7878e85d9d28b633887088fd43c17b4f19e95bd

See more details on using hashes here.

File details

Details for the file pyruvate-1.4.0rc1-cp39-cp39-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.4.0rc1-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 702351f0b376de208a2212deaeb5a376c97a0b1a4a3369673f142e9074cc61f8
MD5 b22fdcea6bbad7337764868ccfe68a57
BLAKE2b-256 6129aa4f4b9fe4e7078f8e7ca4098a0ad5ac5270f6db7142ab4ecbd1f64d28d9

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