From 25094605cf6700bed6a0ed345a13ab9c121685f0 Mon Sep 17 00:00:00 2001 From: benoitc Date: Tue, 27 Aug 2013 18:18:35 +0200 Subject: [PATCH] monkeypatch wsgi.sendfile for gevent make sendfile usage non blocking with gevent --- gunicorn/http/wsgi.py | 2 +- gunicorn/workers/ggevent.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gunicorn/http/wsgi.py b/gunicorn/http/wsgi.py index b8476818..feaf548a 100644 --- a/gunicorn/http/wsgi.py +++ b/gunicorn/http/wsgi.py @@ -18,7 +18,7 @@ try: from os import sendfile except ImportError: try: - from _sendfile import sendfile + from ._sendfile import sendfile except ImportError: sendfile = None diff --git a/gunicorn/workers/ggevent.py b/gunicorn/workers/ggevent.py index 120c2f55..0c00f53f 100644 --- a/gunicorn/workers/ggevent.py +++ b/gunicorn/workers/ggevent.py @@ -5,6 +5,7 @@ from __future__ import with_statement +import errno import os import sys from datetime import datetime @@ -21,13 +22,31 @@ except ImportError: raise RuntimeError("You need gevent installed to use this worker.") from gevent.pool import Pool from gevent.server import StreamServer +from gevent.socket import wait_write from gevent import pywsgi import gunicorn from gunicorn.workers.async import AsyncWorker +from gunicorn.http.wsgi import sendfile as o_sendfile VERSION = "gevent/%s gunicorn/%s" % (gevent.__version__, gunicorn.__version__) +def _gevent_sendfile(fdout, fdin, offset, nbytes): + while True: + try: + return o_sendfile(fdout, fdin, offset, nbytes) + except OSError as e: + if e.args[0] == errno.EAGAIN: + wait_write(fdout) + else: + raise + +def patch_sendfile(): + from gunicorn.http import wsgi + + if o_sendfile is not None: + setattr(wsgi, "sendfile", _gevent_sendfile) + BASE_WSGI_ENV = { 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': VERSION, @@ -50,6 +69,9 @@ class GeventWorker(AsyncWorker): monkey.noisy = False monkey.patch_all() + # monkey patch sendfile to make it none blocking + patch_sendfile() + def notify(self): super(GeventWorker, self).notify() if self.ppid != os.getppid():