Reconcile the Frappe-specific gthread changes with upstream's major
26.0.0 release (HTTP/2, ASGI, lock-free main-thread event loop).
Conflict resolution:
- gunicorn/workers/gthread.py: reimplemented our features on top of
upstream's rewritten event loop instead of merging line-by-line:
- Per-request timeout + faulthandler traceback dump, tracked via an
in-flight future set and keyed on exec_start_time so client-wait
time (upstream's _DEFER path) is excluded and long-lived HTTP/2
connections are exempt.
- Adaptive slow/fast-lane queueing: the request-line peek/classify
now reuses upstream's pending_conns poller-park mechanism, then
dispatches to a fast or slow ThreadPoolExecutor.
- Dropped our eventfd-based shutdown wakeup in favour of upstream's
PollableMethodQueue.defer(), which already wakes the poller on
SIGTERM.
- gunicorn/config.py: kept both new validators; our EnableAdaptiveQueueing
and SlowRequestThreshold settings merged cleanly.
- README.rst was removed upstream (converted to README.md); ported an
updated Fork Information section into README.md.
- tox.ini / .github/workflows/tox.yml: took upstream's Python matrix
(it already drops the EoL versions our fork had pruned).
All gthread + routing tests pass (91), full suite 1976 passed / 263
skipped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Bump version to 25.0.2
- Update copyright year to 2026 in LICENSE and NOTICE
- Add license headers to all Python source files
- Add changelog entry for 25.0.2
Closes#3482
The dirty module (which uses asyncio and concurrent.futures) was being
imported at gunicorn startup via gunicorn.arbiter. This caused
concurrent.futures to be imported before user code could call
gevent.monkey.patch_all(), breaking gevent's monkey-patching.
Changes:
- gunicorn/arbiter.py: Import DirtyArbiter and set_dirty_socket_path
lazily inside spawn_dirty_arbiter() instead of at module level
- gunicorn/dirty/worker.py: Import ThreadPoolExecutor lazily inside
run() method instead of at module level
- Add tests/workers/test_gevent_import_order.py with 5 tests verifying:
- concurrent.futures is NOT imported when gunicorn.arbiter loads
- gevent patching works correctly with gunicorn
- Reproduces the exact scenario from the bug report gist
This ensures gevent's monkey.patch_all() can run before concurrent.futures
is imported, allowing proper patching of threading primitives.
Upgrade minimum eventlet version to 0.40.3 to address security
vulnerabilities:
- CVE-2021-21419 (Moderate 6.9): Websocket memory exhaustion via
large/compressed frames (fixed in 0.31.0)
- CVE-2025-58068 (Moderate 6.3): HTTP Request Smuggling via improper
trailer handling (fixed in 0.40.3)
Also restructure module to call monkey_patch() at import time for
better patching coverage, while keeping hubs.use_hub() in the worker's
patch() method since it creates OS resources that don't survive fork.
Add comprehensive tests for the eventlet worker.
Address CVE-2023-41419 (Critical - remote privilege escalation via
WSGIServer) by requiring gevent 23.9.0 or higher.
Changes:
- Update minimum gevent version from 1.4.0 to 23.9.0
- Remove legacy server.kill() code path (gevent < 1.0)
- Update documentation to reflect new version requirement
- Add comprehensive tests for gevent worker
Fixes#2223.
Unfortunately, eventlet doesn't implement GreenSocket.sendfile, so we have to do it for it.
Add gevent and eventlet to tox.ini and add tests to make sure we can at least import the workers. Some tests that this actually functions would be nice...
Update the gevent and eventlet setup extras to require the versions that are enforced in their worker modules.