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_17 and musllinux_1_1 wheels are available for the x86_64 architecture and active Python 3 versions (currently 3.8-3.12).

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.8) 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.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

This version

1.3.0

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.3.0.tar.gz (61.0 kB view details)

Uploaded Source

Built Distributions

pyruvate-1.3.0-cp312-cp312-musllinux_1_1_x86_64.whl (472.1 kB view details)

Uploaded CPython 3.12 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (474.7 kB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl (472.0 kB view details)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (474.9 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl (472.0 kB view details)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (474.9 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl (472.0 kB view details)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (474.8 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl (472.0 kB view details)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (474.7 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

File details

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

File metadata

  • Download URL: pyruvate-1.3.0.tar.gz
  • Upload date:
  • Size: 61.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.4

File hashes

Hashes for pyruvate-1.3.0.tar.gz
Algorithm Hash digest
SHA256 7debedaa98cb65858ddfff4193a115ca3b207aef803bdb09ef93f854d5ecfdba
MD5 b0334b28d7074cef1299343c4dfa8556
BLAKE2b-256 72e29050c8f85a55305b716967b75d69e377d355940cd2a05c9722135140232a

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp312-cp312-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp312-cp312-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 515cfa85863f793a9be72d95d2dce4c907a94af1fdfbfc24bfcf572907df8e18
MD5 d490a5481b93ab1206b5ca92e6bcc436
BLAKE2b-256 aa3831d84229c957a1ff0cf662f17ba496f4c1f24aa66a1bc8fd3021331b3aa1

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9904ff88213e1725a4fe8ae906fd602520e7e438ac13d4a9f18ceacbcbbd9bfb
MD5 fcd89339d9ccdc2ec2ff63308eda9a8a
BLAKE2b-256 374a4ce29946b3633519f1f634f8988dd89bfeb14a7f41e8a3f7d54f24149177

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 6eb4b60215d3bdf75cbcfc536a6d33cafb70f1d8136d284dfa0a0238cffb2de7
MD5 5fa5ac82a416c80d81548374a787d8c7
BLAKE2b-256 04cd2e67c6340412a9885c29f64d01fa1c95005702f3d7b5ba0bccb5ffbca9dc

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0e87f507fad4d6eb16e8f9a07bf82bf107b0b09fbe582c8c579c6053cc0fdadd
MD5 d9c5dbce0f6fbd4ded1210872cbad3af
BLAKE2b-256 2f175076a641591d161e52b39dc5dcb60f5abf8e4467695f95c158559088c3b4

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 8dd809a6311e3f0255cb43853c5822176fc3bc9efe31876e9c562cbd4cae2dcc
MD5 8864310c5f1622e5ba178b92482b39d6
BLAKE2b-256 449bd9f6dd29f3515eddde7aee779319b12ba000ef5c031eebcd2de23ed69b88

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6bb50688e4a71efff634efde67a0852b8a389e27ad5fe160d76f6202ffe2667b
MD5 a61bedc890c98c772ce961e133d7c638
BLAKE2b-256 aa565fab2c5acef02a06c61dd2c3ec967ed0989f9ce49ee36e5b31bd0ff11a89

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 023203dc5d5260c527804aa59259dacbda0a794d8d367ed14a09a4f3b14f2910
MD5 761e3482dbcd182a63d8e5cd8cf57293
BLAKE2b-256 7ba32cadf846511ac5b87b353b9473f488e5e9806c4962856bee7b979915c570

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8dcbad094d1ca6bec8bc7083b8a9ab28fa879f9b6355433484b2f18cc53c4503
MD5 ef73dde535cb028c3a230c2d606f1b3e
BLAKE2b-256 fd53c4f4ad06ee666c813a9c663bd413643d20620ca6765416c22c5c18347da9

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 ebf7f880c71058d48c96634296412dd71e347372a4087b2ad73084d43c853253
MD5 13ed9907648968608a44ee81949bae86
BLAKE2b-256 2f02426249090c8a21a1506d46cc079c10a0a74f1b734cd5cd3aa14a76570e08

See more details on using hashes here.

File details

Details for the file pyruvate-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a99ba7e6c9a02eb92ac383193bfff11e30b6015d6ed132510f826cdfb6fa8741
MD5 2d7dea2ba3d145102c1bedff58d4378f
BLAKE2b-256 df0a1c05eaf3328554fecd42513501ff36f0cce8661c6e3205645fce5a3bf764

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