From 95c31acb27e7d209b83c867f581d0e3baef8e0c5 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Mon, 16 May 2016 21:41:26 -0400 Subject: [PATCH] Implement a gunicorn worker that uses uvloop --- .travis.yml | 3 +++ aiohttp/worker.py | 19 ++++++++++++++++++- docs/gunicorn.rst | 6 ++++++ tests/test_worker.py | 26 ++++++++++++++++++++++---- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0b08ce660a6..4845bc0edce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,9 @@ install: - pip install -r requirements-ci.txt - pip install aiodns - pip install coveralls + - if python -c "import sys; sys.exit(sys.version_info < (3,5))"; then + pip install uvloop; + fi script: - flake8 aiohttp diff --git a/aiohttp/worker.py b/aiohttp/worker.py index 593962d3a4c..9a8fd3e3a72 100644 --- a/aiohttp/worker.py +++ b/aiohttp/worker.py @@ -9,7 +9,7 @@ from aiohttp.helpers import ensure_future -__all__ = ('GunicornWebWorker',) +__all__ = ('GunicornWebWorker', 'GunicornUVLoopWebWorker') class GunicornWebWorker(base.Worker): @@ -129,3 +129,20 @@ def handle_quit(self, sig, frame): def handle_abort(self, sig, frame): self.alive = False self.exit_code = 1 + + +class GunicornUVLoopWebWorker(GunicornWebWorker): + + def init_process(self): + import uvloop + + # Close any existing event loop before setting a + # new policy. + asyncio.get_event_loop().close() + + # Setup uvloop policy, so that every + # asyncio.get_event_loop() will create an instance + # of uvloop event loop. + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + + super().init_process() diff --git a/docs/gunicorn.rst b/docs/gunicorn.rst index 12d0c6dc21d..01e5dc4ed91 100644 --- a/docs/gunicorn.rst +++ b/docs/gunicorn.rst @@ -84,6 +84,12 @@ aiohttp.wsgi applications:: Gunicorn is now running and ready to serve requests to your app's worker processes. +.. note:: + + If you want to use an alternative asyncio event loop + `uvloop `_, you can use the + ``aiohttp.worker.GunicornUVLoopWebWorker`` worker class. + More information ---------------- diff --git a/tests/test_worker.py b/tests/test_worker.py index 79d909c4fe5..36183c0bc49 100644 --- a/tests/test_worker.py +++ b/tests/test_worker.py @@ -1,13 +1,16 @@ """Tests for aiohttp/worker.py""" import asyncio import pytest +import sys +import unittest + from unittest import mock base_worker = pytest.importorskip('aiohttp.worker') -class MyWorker(base_worker.GunicornWebWorker): +class BaseTestWorker: def __init__(self): self.servers = [] @@ -16,9 +19,24 @@ def __init__(self): self.cfg.graceful_timeout = 100 -@pytest.fixture -def worker(): - return MyWorker() +class AsyncioWorker(BaseTestWorker, base_worker.GunicornWebWorker): + pass + + +class UvloopWorker(BaseTestWorker, base_worker.GunicornUVLoopWebWorker): + + def __init__(self): + if sys.version_info < (3, 5) \ + or sys.platform in ('win32', 'cygwin', 'cli'): + # uvloop requires Python 3.5 and *nix. + raise unittest.SkipTest() + + super().__init__() + + +@pytest.fixture(params=[AsyncioWorker, UvloopWorker]) +def worker(request): + return request.param() def test_init_process(worker):