Skip to content

Commit

Permalink
Fix eventlet shutdown to actively shut down the workers.
Browse files Browse the repository at this point in the history
  • Loading branch information
tilgovi committed Nov 18, 2014
1 parent fcba1a6 commit 415956d
Showing 1 changed file with 49 additions and 8 deletions.
57 changes: 49 additions & 8 deletions gunicorn/workers/geventlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from functools import partial
import errno
import sys

try:
import eventlet
Expand All @@ -16,9 +17,10 @@
raise RuntimeError("You need eventlet >= 0.9.7")


from eventlet import hubs
from eventlet import hubs, greenthread
from eventlet.greenio import GreenSocket
from eventlet.hubs import trampoline
import greenlet

from gunicorn.http.wsgi import sendfile as o_sendfile
from gunicorn.workers.async import AsyncWorker
Expand All @@ -33,6 +35,47 @@ def _eventlet_sendfile(fdout, fdin, offset, nbytes):
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:
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

Expand Down Expand Up @@ -60,16 +103,13 @@ def handle(self, listener, client, addr):

super(EventletWorker, self).handle(listener, client, addr)

if not self.alive:
raise eventlet.StopServe()

def run(self):
acceptors = []
for sock in self.sockets:
sock = GreenSocket(sock)
sock.setblocking(1)
hfun = partial(self.handle, sock)
acceptor = eventlet.spawn(eventlet.serve, sock, hfun,
gsock = GreenSocket(sock)
gsock.setblocking(1)
hfun = partial(self.handle, gsock)
acceptor = eventlet.spawn(_eventlet_serve, gsock, hfun,
self.worker_connections)

acceptors.append(acceptor)
Expand All @@ -82,6 +122,7 @@ def run(self):
self.notify()
try:
with eventlet.Timeout(self.cfg.graceful_timeout) as t:
[a.kill(eventlet.StopServe()) for a in acceptors]
[a.wait() for a in acceptors]
except eventlet.Timeout as te:
if te != t:
Expand Down

0 comments on commit 415956d

Please sign in to comment.