Add chunked transfer encoding support to the ASGI worker for HTTP/1.1
streaming responses that don't have a Content-Length header. This fixes
SSE (Server-Sent Events) connections not closing properly.
Without chunked encoding or Content-Length, HTTP/1.1 clients wait for
the connection to close to determine end-of-response, causing streaming
endpoints to hang.
Also updates the celery_alternative example to use FastAPI with the
native ASGI worker and uvloop, demonstrating async task execution with
proper SSE streaming.
- Add explicit do_handshake() in base_async.py before ALPN check
when do_handshake_on_connect is False
- Mark eventlet worker as deprecated (removal in 26.0)
- Add HTTP/2 gevent example with Docker and tests
- Update documentation to reflect eventlet deprecation
- Remove eventlet websocket example (gevent version exists)
The ALPN fix ensures HTTP/2 works correctly with gevent and eventlet
workers when do_handshake_on_connect config is False (the default).
Without explicit handshake, selected_alpn_protocol() returns None.
Add complete HTTP/2 example in examples/http2_features/:
- ASGI app showing priority access and trailer sending
- Test script using raw h2 library for HTTP/2 testing
- Docker setup for easy testing
- Documentation update referencing the example
The example demonstrates:
- Reading http.response.priority extension in ASGI scope
- Sending http.response.trailers messages
- Multiple streams on the same connection
Add a lightweight chat simulator demonstrating dirty worker streaming:
- Token-by-token SSE streaming via async generators
- FastAPI endpoint with browser UI
- Multiple canned responses based on keywords
- Docker deployment with docker-compose
- Integration tests for SSE protocol
Update docs/content/dirty.md to link to both examples.
Add a complete example demonstrating dirty workers with sentence-transformers
for text embeddings via FastAPI:
- EmbeddingApp DirtyApp that loads and manages the ML model
- FastAPI endpoints for /embed and /health
- Docker and docker-compose configuration
- Integration tests with numpy similarity checks
- GitHub Actions CI workflow
Introduce Dirty Arbiters - a separate process pool for executing
long-running, blocking operations (AI model loading, heavy computation)
without blocking HTTP workers. Inspired by Erlang's dirty schedulers.
Key features:
- Completely separate from HTTP workers - can be killed/restarted independently
- Stateful - loaded resources persist in dirty worker memory
- Message-passing IPC via Unix sockets with JSON serialization
- Explicit execute() API from HTTP workers
- Asyncio-based for clean concurrent handling
Architecture:
- DirtyArbiter: manages the dirty worker pool, routes requests
- DirtyWorker: executes functions, maintains state, handles requests
- DirtyClient: sync/async API for HTTP workers to call dirty apps
- DirtyProtocol: length-prefixed JSON messages over Unix sockets
- DirtyApp: base class for dirty applications
Configuration options:
- dirty_apps: list of import paths for dirty applications
- dirty_workers: number of dirty workers (default: 0)
- dirty_timeout: task timeout in seconds (default: 300)
- dirty_graceful_timeout: shutdown timeout (default: 30)
Lifecycle hooks:
- on_dirty_starting(arbiter)
- dirty_post_fork(arbiter, worker)
- dirty_worker_init(worker)
- dirty_worker_exit(arbiter, worker)
Includes comprehensive test suite with 164 tests covering:
- Protocol encoding/decoding
- Worker and arbiter lifecycle
- Client sync/async APIs
- Signal handling
- Error handling and timeouts
- Integration tests
- Bump version to 24.1.0
- Add PROXY protocol v2 documentation to deploy guide
- Add 24.1.0 changelog with new features and bug fixes
- Update all docs.gunicorn.org URLs to gunicorn.org
Update minimum Tornado version to 6.5.0 to address:
- CVE-2024-52804 (Medium): HTTP Cookie Parsing DoS
- CVE-2025-47287 (High 7.5): Multipart/Form-Data Parser DoS
This simplifies the tornado worker by removing legacy code paths
for Tornado < 5.0 and < 6.0, reducing the codebase by ~30%.
Changes:
- pyproject.toml: Update tornado requirement to >=6.5.0
- gtornado.py: Remove TORNADO5 constant and legacy code paths
- tornadoapp.py: Update example to use async/await syntax
- test_gtornado.py: Add comprehensive test suite
Add a new ASGI worker type that provides native async support using
gunicorn's own HTTP parsing infrastructure adapted for asyncio.
Features:
- HTTP/1.1 with keepalive support
- WebSocket connections (RFC 6455)
- ASGI lifespan protocol for startup/shutdown hooks
- Optional uvloop support for improved performance
- Full proxy protocol support (inherited from gunicorn)
New configuration options:
- --asgi-loop: Event loop selection (auto/asyncio/uvloop)
- --asgi-lifespan: Lifespan protocol control (auto/on/off)
- --root-path: ASGI root path for reverse proxy setups
Usage: gunicorn -k asgi myapp:app
since 3.3: EnvironmentError, IOError, socket.error and select.error are merged into IOError.
They may now return a more specific subclass - which this commit does not utilize yet.
* Change deprecated ssl.wrap_socket() to SSLContext.wrap_context().
* Add new server hook to allow user to create custom SSLContext.
* Updated the documentation.
Signed-off-by: Tero Saarni <tero.saarni@est.tech>
This commit reverts one aspect changed by 5f4ebd2eb2b08783a5fbefe79d09fcb3fc1fbc73 (#1151);
header-values are again encoded as latin-1 and not ascii. Test is restored but uses
a latin-1-mappable test-character, not a general utf8 character.
Fixed#1778.
Signed-off-by: Brett Randall <javabrett@gmail.com>
PID didn't work at all on Ubuntu 16.04 with the provided sample, my commented out change does, also added logging change to conform to what is out of the box.