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. This version is a release candidate that is replacing the now inactive rust-cpython crate with PyO3.

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

Uploaded Source

Built Distributions

pyruvate-1.3.0rc1-cp312-cp312-musllinux_1_1_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0rc1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0rc1-cp311-cp311-musllinux_1_1_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0rc1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0rc1-cp310-cp310-musllinux_1_1_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0rc1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0rc1-cp39-cp39-musllinux_1_1_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0rc1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pyruvate-1.3.0rc1-cp38-cp38-musllinux_1_1_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

pyruvate-1.3.0rc1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

File details

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

File metadata

  • Download URL: pyruvate-1.3.0rc1.tar.gz
  • Upload date:
  • Size: 61.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.6

File hashes

Hashes for pyruvate-1.3.0rc1.tar.gz
Algorithm Hash digest
SHA256 af268c4d167059d017dbcf5d6e9c5e49567d40e30416a58bcb0b05775a9c0c1d
MD5 d97d7bc4e9d1e1147876adbbd02a4f50
BLAKE2b-256 2ed99825934d730eb41f41c7fed361fe47ca0009994626641894c695834111b3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp312-cp312-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 a6f238178e76c6387207a4e494b7cc9e33c4b36bdf4134b380443efdde4b45d6
MD5 a35115d25915fe471b8f3aca44d4fa94
BLAKE2b-256 578413ba1215e4098b6ab2cc3d4513454c39a75d027dfcaa3f79000727efa22b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 613357720ebc7ed3d239ae008c0b0d94f8c3471558d7ac474eba678eaeecae8e
MD5 f9f32858ecf86ba3ad11108e4e3996cb
BLAKE2b-256 e510ade6bd66bdb34ab774a30f60aa75b97a28229129db91c8f848a938832c46

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp311-cp311-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 7b49f2ebaaece65f11c5b343b267894baa74414bd3c4a9c375009eb51397218d
MD5 005fc7bcf2f120e1391797c9b19f987c
BLAKE2b-256 0dc97b8264ce77c89ff62c095605ba2c827a4fd40fa46fa1aa6451d8844d81cf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8225a7c7af5644a9ca52eadbba2e2b7ad108e663d4472e49e3f010689cdf8241
MD5 8a824e041ff1e2332bd3f4cb12cfee18
BLAKE2b-256 61834fd2c91e60ddff6fdad3c3dc26324f1ee7f62936b6b0d4366c9866583920

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp310-cp310-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 8f9d36f719634a5fb76e85488a2853c76eafc3d0d942d7e9b8025c7a362bf3fb
MD5 331150b83b3ccf5b0d7d1e769ce2b387
BLAKE2b-256 6fe12691b3d32c405e13840fbf3a854f2c0bdd2c1f36e515a01a23b1ef6b04a5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2aa08b80167945cb3009d61766195045595d2b623f1e1bdd83e8e71eebc797ec
MD5 a801389b0342f78d7d953839235ac67f
BLAKE2b-256 da59a56f2440d261d2483b3a56ce509d74230c7c88f1259b409d89bf35285017

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp39-cp39-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 343b1f8469ce3a245924bc6d175da40841c3bca7f3c6c382c1b62b9c2d910bbc
MD5 60f07860ce70ae389c2a4e928555a7a3
BLAKE2b-256 d532de64a3d4875d8f82b9c0aeb27bff9968c15048b4a715d1bcab435ad23a13

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c4edee19c31fb3ad6bd665c7514a0f8c5ba75c51b4231bf8662f740d3a2fa5ef
MD5 33a95dc418d06df9d7b00b8b06a25a45
BLAKE2b-256 2a9f6bdd3083459ad3141358b8787ac8bbd4f530bce8f91212eda7cf07eccece

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp38-cp38-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 f3dd4f06a49ab258c1468c21bbd3e92558942a5f764527611b8708d34658598f
MD5 85c204c3fe38c11fa3569bdc8f350355
BLAKE2b-256 eabbcbd5e8ffb547e4ce22fd62f17b99bc0cb47cf059da28239f518d9398fa55

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyruvate-1.3.0rc1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 11dc73381ca70154b320ca5e948d7ac17c21bb795e0252b87fdb8bb283b49872
MD5 f64e24bbdebb38630e6800343a2a259e
BLAKE2b-256 531a30e29f97de7ce5c9f58348e3cd08ce8913bba148afbaa17be09fb9319e64

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