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

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

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

Uploaded Source

Built Distributions

pyruvate-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

pyruvate-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pyruvate-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

pyruvate-1.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pyruvate-1.2.2-cp39-cp39-musllinux_1_1_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

pyruvate-1.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pyruvate-1.2.2-cp38-cp38-musllinux_1_1_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

pyruvate-1.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

pyruvate-1.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.7m musllinux: musl 1.1+ x86-64

pyruvate-1.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

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

File details

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

File metadata

  • Download URL: pyruvate-1.2.2.tar.gz
  • Upload date:
  • Size: 60.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.2

File hashes

Hashes for pyruvate-1.2.2.tar.gz
Algorithm Hash digest
SHA256 2740901764fe9f3aaa252c4fcc8efc591a8196929d1a91a39b0ad48d75e56bcd
MD5 b7f33ee7a08f26de649147dae39a2468
BLAKE2b-256 367b1f61bbb94ce211f9b914d4edf2ad3149eac1af5ca1fe4c0a0be6c95439a7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 8af2eb19c851d7484814e6eab2f6d6d98a9256a236208c43c1da9bddb3036ba6
MD5 69d7bc1f70e802da5eded9196201c8d8
BLAKE2b-256 72855dae28e98ff48ef41e44c8a09c5450e06aaf91d18ff05994ddaed2e5e4b4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2644333fc8fc9eaddbaefcd4eaca3c12d866c64d77be9c1617b0859a0ea68aa6
MD5 15e08f68073688fb7c8ec8f97b2f0515
BLAKE2b-256 86cdf6bfd0039b52ccf486e2d5d7b814d29d234cfa327cd5618c35c86463a116

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 e17e5e947981385088730605ebb27dc46413b057312e34f6fb2a5a99bab37c96
MD5 7e8ebb02cd44609942ee65215f5e4778
BLAKE2b-256 1f5cc33cfd2b0a64bc9dec542e96c271fb83883bcccf73f7b4824eb3141865e9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 aa0892a6ac51680036ed5cfff0ef0bc29a1460dcdc4be76e8270e72f7c686b61
MD5 517009002bb968d2bcf249fbbe35b0ea
BLAKE2b-256 ad4cd3f5db26906f343b07a82de3f06a77a0469b21d5dbf85a355dcac21db0ce

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp39-cp39-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 a2c8bd7bf14765f3a3f37c5da7a17983340a2315376a12564f2826dfa07f8f8c
MD5 1f7fcf38e995d0fbf6f1fb71314b0767
BLAKE2b-256 2abc12ce329d9c431bdb902bcb43cafd7e19757217c3be580099febb8f1371ee

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fd10f1718989063cadce40e91d1a721dc49a2bb5fa84e4a9f60bea895dc043cd
MD5 aaed6aea28aee1233422e9259d1adf36
BLAKE2b-256 2c2f39392db440898e5906b1ab3b1717f64ab8743d6898480d0d36135ced9a9d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp38-cp38-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 b8d2832e75ce29174608cd8fedeacdfdefaa216e3dc3f77f1e8b791145ff1f37
MD5 e3b04c509bfbfd620bc3508ed9e244de
BLAKE2b-256 62f94162bbaaed2625abaf86dea7a790510e1335d05a7e7b9fe5760d99e4a63c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 721438a9a45bd2cb3d90b00132154f87229a2287e8b3ac35928aa5b425e0e767
MD5 6663a5c000bad922bff6806b93dfb43e
BLAKE2b-256 cb61c6dea9a950f7f4414d4a8d0b4a12ed3e876e25eed9d1331f7db05ec488fa

See more details on using hashes here.

File details

Details for the file pyruvate-1.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 bde8bde487b5206210d265d7e82e153615aeb1ed2e2672dc349121b40198c5f1
MD5 4831a2950138a7e3362c81f70649317d
BLAKE2b-256 90d935b51c8232b9be59e5bb33e8e49d93813a25a025e72edfb0c22ea97eb78e

See more details on using hashes here.

File details

Details for the file pyruvate-1.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyruvate-1.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e1c42de49156bc2608ab6f8ccab01cd2188891f02be031af14d81732e409fbbe
MD5 642e941bd93e20da8c395465c3b5243e
BLAKE2b-256 527314ca181dbd4b40886bae7b8bb357f12aba900480710c18965fd97b95f5db

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