Skip to content

Commit d7a1a53

Browse files
authored
Merge pull request #1196 from alphagov/ris-gunicorn-context-recycling-eventlet-worker
eventlet: add `ContextRecyclingEventletWorker`
2 parents a6b6dd1 + 2176c52 commit d7a1a53

File tree

5 files changed

+43
-1
lines changed

5 files changed

+43
-1
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# CHANGELOG
22

3+
## 96.0.0
4+
5+
* BREAKING CHANGE: the `gunicorn_defaults` module has been moved to `gunicorn.defaults` to make space for gunicorn-related utils that don't have the restricted-import constraints of the gunicorn defaults. Imports of `notifications_utils.gunicorn_defaults` should be changed to `notifications_utils.gunicorn.defaults`.
6+
* Added `ContextRecyclingEventletWorker` custom gunicorn worker class.
7+
38
## 95.2.0
49

510
* Implement `InsensitiveSet.__contains__`
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Avoid additions to this file as it will implicitly be imported before all
2+
# notifications_utils.gunicorn.* imports and we need to be able to use the
3+
# defaults module from an early stage of app bringup
File renamed without changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import contextvars
2+
from collections import deque
3+
4+
import greenlet
5+
from gunicorn.workers import geventlet
6+
7+
8+
class ContextRecyclingEventletWorker(geventlet.EventletWorker):
9+
"""
10+
Because eventlet's GreenPool discards GreenThreads after they have performed a task,
11+
to reduce wasteful continual re-creation of thread-local resources this class will
12+
maintain a pool of thread contexts suitable for reuse with new GreenThreads. In
13+
theory at least this means we will never have more thread contexts than the maximum
14+
number of concurrent GreenThreads handling connections we've ever had.
15+
"""
16+
17+
def __init__(self, *args, **kwargs):
18+
self.context_pool = deque() # a stack of unused thread contexts
19+
super().__init__(*args, **kwargs)
20+
21+
def handle(self, *args, **kwargs):
22+
g = greenlet.getcurrent()
23+
if self.context_pool:
24+
# reuse an existing thread context from the pool
25+
g.gr_context = self.context_pool.pop()
26+
27+
ret = super().handle(*args, **kwargs)
28+
29+
# stash potentially-populated thread context in context_pool
30+
self.context_pool.append(g.gr_context)
31+
# replace reference to now-stashed context with an empty one
32+
g.gr_context = contextvars.Context()
33+
34+
return ret

notifications_utils/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
# - `make version-minor` for new features
66
# - `make version-patch` for bug fixes
77

8-
__version__ = "95.2.0" # e423953f9dec74010897c62aa4e035de
8+
__version__ = "96.0.0" # 6fdd72884bdeadbeef

0 commit comments

Comments
 (0)