You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							148 lines
						
					
					
						
							4.2 KiB
						
					
					
				
			
		
		
	
	
							148 lines
						
					
					
						
							4.2 KiB
						
					
					
				# -*- coding: utf-8 -
 | 
						|
#
 | 
						|
# This file is part of gunicorn released under the MIT license.
 | 
						|
# See the NOTICE for more information.
 | 
						|
 | 
						|
from functools import partial
 | 
						|
import errno
 | 
						|
import sys
 | 
						|
 | 
						|
try:
 | 
						|
    import eventlet
 | 
						|
except ImportError:
 | 
						|
    raise RuntimeError("You need eventlet installed to use this worker.")
 | 
						|
 | 
						|
# validate the eventlet version
 | 
						|
if eventlet.version_info < (0, 9, 7):
 | 
						|
    raise RuntimeError("You need eventlet >= 0.9.7")
 | 
						|
 | 
						|
 | 
						|
from eventlet import hubs, greenthread
 | 
						|
from eventlet.greenio import GreenSocket
 | 
						|
from eventlet.hubs import trampoline
 | 
						|
from eventlet.wsgi import ALREADY_HANDLED as EVENTLET_ALREADY_HANDLED
 | 
						|
import greenlet
 | 
						|
 | 
						|
from gunicorn.http.wsgi import sendfile as o_sendfile
 | 
						|
from gunicorn.workers.async import AsyncWorker
 | 
						|
 | 
						|
def _eventlet_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:
 | 
						|
                trampoline(fdout, write=True)
 | 
						|
            else:
 | 
						|
                raise
 | 
						|
 | 
						|
 | 
						|
def _eventlet_serve(sock, handle, concurrency):
 | 
						|
    """
 | 
						|
    Serve requests forever.
 | 
						|
 | 
						|
    This code is nearly identical to ``eventlet.convenience.serve`` except
 | 
						|
    that it attempts to join the pool at the end, which allows for gunicorn
 | 
						|
    graceful shutdowns.
 | 
						|
    """
 | 
						|
    pool = eventlet.greenpool.GreenPool(concurrency)
 | 
						|
    server_gt = eventlet.greenthread.getcurrent()
 | 
						|
 | 
						|
    while True:
 | 
						|
        try:
 | 
						|
            conn, addr = sock.accept()
 | 
						|
            gt = pool.spawn(handle, conn, addr)
 | 
						|
            gt.link(_eventlet_stop, server_gt, conn)
 | 
						|
            conn, addr, gt = None, None, None
 | 
						|
        except eventlet.StopServe:
 | 
						|
            sock.close()
 | 
						|
            pool.waitall()
 | 
						|
            return
 | 
						|
 | 
						|
 | 
						|
def _eventlet_stop(client, server, conn):
 | 
						|
    """
 | 
						|
    Stop a greenlet handling a request and close its connection.
 | 
						|
 | 
						|
    This code is lifted from eventlet so as not to depend on undocumented
 | 
						|
    functions in the library.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        try:
 | 
						|
            client.wait()
 | 
						|
        finally:
 | 
						|
            conn.close()
 | 
						|
    except greenlet.GreenletExit:
 | 
						|
        pass
 | 
						|
    except Exception:
 | 
						|
        greenthread.kill(server, *sys.exc_info())
 | 
						|
 | 
						|
 | 
						|
def patch_sendfile():
 | 
						|
    from gunicorn.http import wsgi
 | 
						|
 | 
						|
    if o_sendfile is not None:
 | 
						|
        setattr(wsgi, "sendfile", _eventlet_sendfile)
 | 
						|
 | 
						|
 | 
						|
class EventletWorker(AsyncWorker):
 | 
						|
 | 
						|
    def patch(self):
 | 
						|
        hubs.use_hub()
 | 
						|
        eventlet.monkey_patch(os=False)
 | 
						|
        patch_sendfile()
 | 
						|
 | 
						|
    def is_already_handled(self, respiter):
 | 
						|
        if respiter == EVENTLET_ALREADY_HANDLED:
 | 
						|
            raise StopIteration()
 | 
						|
        else:
 | 
						|
            return super(EventletWorker, self).is_already_handled(respiter)
 | 
						|
 | 
						|
    def init_process(self):
 | 
						|
        super(EventletWorker, self).init_process()
 | 
						|
        self.patch()
 | 
						|
 | 
						|
    def handle_quit(self, sig, frame):
 | 
						|
        eventlet.spawn(super(EventletWorker, self).handle_quit, sig, frame)
 | 
						|
 | 
						|
    def handle_usr1(self, sig, frame):
 | 
						|
        eventlet.spawn(super(EventletWorker, self).handle_usr1, sig, frame)
 | 
						|
 | 
						|
    def timeout_ctx(self):
 | 
						|
        return eventlet.Timeout(self.cfg.keepalive or None, False)
 | 
						|
 | 
						|
    def handle(self, listener, client, addr):
 | 
						|
        if self.cfg.is_ssl:
 | 
						|
            client = eventlet.wrap_ssl(client, server_side=True,
 | 
						|
                                       **self.cfg.ssl_options)
 | 
						|
 | 
						|
        super(EventletWorker, self).handle(listener, client, addr)
 | 
						|
 | 
						|
    def run(self):
 | 
						|
        acceptors = []
 | 
						|
        for sock in self.sockets:
 | 
						|
            gsock = GreenSocket(sock)
 | 
						|
            gsock.setblocking(1)
 | 
						|
            hfun = partial(self.handle, gsock)
 | 
						|
            acceptor = eventlet.spawn(_eventlet_serve, gsock, hfun,
 | 
						|
                                      self.worker_connections)
 | 
						|
 | 
						|
            acceptors.append(acceptor)
 | 
						|
            eventlet.sleep(0.0)
 | 
						|
 | 
						|
        while self.alive:
 | 
						|
            self.notify()
 | 
						|
            eventlet.sleep(1.0)
 | 
						|
 | 
						|
        self.notify()
 | 
						|
        try:
 | 
						|
            with eventlet.Timeout(self.cfg.graceful_timeout) as t:
 | 
						|
                for a in acceptors:
 | 
						|
                    a.kill(eventlet.StopServe())
 | 
						|
                for a in acceptors:
 | 
						|
                    a.wait()
 | 
						|
        except eventlet.Timeout as te:
 | 
						|
            if te != t:
 | 
						|
                raise
 | 
						|
            for a in acceptors:
 | 
						|
                a.kill()
 | 
						|
 |