Tino
Tino

Reputation: 91

Exact command to use gunicorn with pypy

I've searched Google but can't seem to find an example of the command to use pypy with gunicorn. My current command to start gunicorn looks like this:

gunicorn = subprocess.Popen(['gunicorn', 
                             '-k', 'gevent', 
                             '-b', 'unix:/dev/shm/gunicorn.sock', 
                             '-w', '4', 
                             'wsgi:app'])

I have tried the following:

gunicorn = subprocess.Popen(['pypy', 'gunicorn', 
                             '-k', 'gevent', 
                             '-b', 'unix:/dev/shm/gunicorn.sock', 
                             '-w', '4', 
                             'wsgi:app'])

and

gunicorn = subprocess.Popen(['gunicorn', 
                             '-k', 'gevent', 
                             '-b', 'unix:/dev/shm/gunicorn.sock', 
                             '-w', '4', 
                             'pypy', 'wsgi:app'])

but both did not work.

So my question is, how exactly can I start my app (wsgi:app) using pypy within the gunicorn command?

Upvotes: 2

Views: 1988

Answers (2)

Cees Timmerman
Cees Timmerman

Reputation: 19644

In Mint, this appears to work:

mkdir api_test && cd $_
apt install pypy3 siege
pypy3 -m venv .venv_pypy3
source .venv_pypy3/bin/activate
pypy3 -m pip install gunicorn
nano gunicorn_test.py

Paste:

import multiprocessing

import gunicorn.app.base


def number_of_workers():
    return (multiprocessing.cpu_count() * 2) + 1


def handler_app(environ, start_response):
    response_body = b'Works fine'
    status = '200 OK'

    response_headers = [
        ('Content-Type', 'text/plain'),
    ]

    start_response(status, response_headers)

    return [response_body]


class StandaloneApplication(gunicorn.app.base.BaseApplication):

    def __init__(self, app, options=None):
        self.options = options or {}
        self.application = app
        super().__init__()

    def load_config(self):
        config = {key: value for key, value in self.options.items()
                  if key in self.cfg.settings and value is not None}
        for key, value in config.items():
            self.cfg.set(key.lower(), value)

    def load(self):
        return self.application


if __name__ == '__main__':
    options = {
        'bind': '%s:%s' % ('127.0.0.1', '8080'),
        'workers': number_of_workers(),
    }
    StandaloneApplication(handler_app, options).run()

Run:

pypy3 gunicorn_test.py

Benchmark in new terminal for client:

$ siege --benchmark --time=20s --concurrent=20 http://127.0.0.1:8080
** SIEGE 4.0.4
** Preparing 20 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions:              85638 hits
Availability:             100.00 %
Elapsed time:              19.30 secs
Data transferred:           0.82 MB
Response time:              0.00 secs
Transaction rate:        4437.20 trans/sec
Throughput:             0.04 MB/sec
Concurrency:               19.66
Successful transactions:       85638
Failed transactions:               0
Longest transaction:            0.14
Shortest transaction:           0.00

Note that siege will hang here if using too high a concurrency! 200 was no problem in uvicorn on pypy3. I'm testing best of 3 in a VirtualBox on Windows 10 using 75% memory according to Process Hacker. CPython appears to be less demanding:

Python3 setup in server terminal:

deactivate
apt install python3-venv
python3 -m venv .venv_python3
source .venv_python3/bin/activate
python3 -m pip install gunicorn
python3 gunicorn_test.py

Benchmark in (new) client terminal:

$ siege --benchmark --time=20s --concurrent=20 http://127.0.0.1:8080
** SIEGE 4.0.4
** Preparing 20 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions:              65340 hits
Availability:             100.00 %
Elapsed time:              19.02 secs
Data transferred:           0.62 MB
Response time:              0.01 secs
Transaction rate:        3435.33 trans/sec
Throughput:             0.03 MB/sec
Concurrency:               19.71
Successful transactions:       65340
Failed transactions:               0
Longest transaction:            0.16
Shortest transaction:           0.00

Upvotes: 2

Kha Man
Kha Man

Reputation: 1

Gunicorn stays in the folder Scripts, so it depends. Make sure when you make gunicorn available global by using os environment, it stays in Pypy's subfolder.

Upvotes: -1

Related Questions