mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-02 18:51:31 +08:00
345 lines
14 KiB
Markdown
345 lines
14 KiB
Markdown
<span id="news-2026"></span>
|
||
# Changelog - 2026
|
||
|
||
## 25.2.0 - 2026-03-24
|
||
|
||
### New Features
|
||
|
||
- **Fast HTTP Parser (gunicorn_h1c 0.4.1)**: Integrate new exception types and limit
|
||
parameters from gunicorn_h1c 0.4.1 for both WSGI and ASGI workers
|
||
- Requires gunicorn_h1c >= 0.4.1 for `http_parser='fast'`
|
||
- Falls back to Python parser in `auto` mode if version not met
|
||
- Proper HTTP status codes for limit errors (414, 431)
|
||
|
||
### Bug Fixes
|
||
|
||
- **uWSGI Async Workers**: Fix `InvalidUWSGIHeader: incomplete header` error
|
||
when using gevent or gthread workers with uwsgi protocol behind nginx.
|
||
([#3552](https://github.com/benoitc/gunicorn/issues/3552),
|
||
[PR #3554](https://github.com/benoitc/gunicorn/pull/3554))
|
||
|
||
- **FileWrapper Iterator Protocol**: Add `__iter__` and `__next__` methods to
|
||
`FileWrapper` for full PEP 3333 compliance. Previously only supported old-style
|
||
`__getitem__` iteration which broke code explicitly using `iter()` or `next()`.
|
||
([#3396](https://github.com/benoitc/gunicorn/issues/3396),
|
||
[PR #3550](https://github.com/benoitc/gunicorn/pull/3550))
|
||
|
||
### Performance
|
||
|
||
- **ASGI HTTP Parser Optimizations**: Improve ASGI worker HTTP parsing performance
|
||
- Read chunks in 64-byte blocks instead of 1 byte at a time for chunk size lines and trailers
|
||
- Reuse BytesIO buffers with truncate/seek instead of creating new objects (reduces GC pressure)
|
||
- Use `bytearray.find()` directly instead of converting to bytes first
|
||
- Use index-based iteration for header parsing instead of `list.pop(0)` (O(1) vs O(n))
|
||
|
||
---
|
||
|
||
## 25.1.0 - 2026-02-13
|
||
|
||
### New Features
|
||
|
||
- **Control Interface (gunicornc)**: Add interactive control interface for managing
|
||
running Gunicorn instances, similar to birdc for BIRD routing daemon
|
||
([PR #3505](https://github.com/benoitc/gunicorn/pull/3505))
|
||
- Unix socket-based communication with JSON protocol
|
||
- Interactive mode with readline support and command history
|
||
- Commands: `show all/workers/dirty/config/stats/listeners`
|
||
- Worker management: `worker add/remove/kill`, `dirty add/remove`
|
||
- Server control: `reload`, `reopen`, `shutdown`
|
||
- New settings: `--control-socket`, `--control-socket-mode`, `--no-control-socket`
|
||
- New CLI tool: `gunicornc` for connecting to control socket
|
||
- See [Control Interface Guide](guides/gunicornc.md) for details
|
||
|
||
- **Dirty Stash**: Add global shared state between workers via `dirty.stash`
|
||
([PR #3503](https://github.com/benoitc/gunicorn/pull/3503))
|
||
- In-memory key-value store accessible by all workers
|
||
- Supports get, set, delete, clear, keys, and has operations
|
||
- Useful for sharing state like feature flags, rate limits, or cached data
|
||
|
||
- **Dirty Binary Protocol**: Implement efficient binary protocol for dirty arbiter IPC
|
||
using TLV (Type-Length-Value) encoding
|
||
([PR #3500](https://github.com/benoitc/gunicorn/pull/3500))
|
||
- More efficient than JSON for binary data
|
||
- Supports all Python types: str, bytes, int, float, bool, None, list, dict
|
||
- Better performance for large payloads
|
||
|
||
- **Dirty TTIN/TTOU Signals**: Add dynamic worker scaling for dirty arbiters
|
||
([PR #3504](https://github.com/benoitc/gunicorn/pull/3504))
|
||
- Send SIGTTIN to increase dirty workers
|
||
- Send SIGTTOU to decrease dirty workers
|
||
- Respects minimum worker constraints from app configurations
|
||
|
||
### Changes
|
||
|
||
- **ASGI Worker**: Promoted from beta to stable
|
||
- **Dirty Arbiters**: Now marked as beta feature
|
||
|
||
### Documentation
|
||
|
||
- Fix Markdown formatting in /configure documentation
|
||
|
||
---
|
||
|
||
## 25.0.3 - 2026-02-07
|
||
|
||
### Bug Fixes
|
||
|
||
- Fix RuntimeError when StopIteration is raised inside ASGI response body
|
||
coroutine (PEP 479 compliance)
|
||
|
||
- Fix deprecation warning for passing maxsplit as positional argument in
|
||
`re.split()` (Python 3.13+)
|
||
|
||
---
|
||
|
||
## 25.0.2 - 2026-02-06
|
||
|
||
### Bug Fixes
|
||
|
||
- Fix ASGI concurrent request failures through nginx proxy by normalizing
|
||
sockaddr tuples to handle both 2-tuple (IPv4) and 4-tuple (IPv6) formats
|
||
([PR #3485](https://github.com/benoitc/gunicorn/pull/3485))
|
||
|
||
- Fix graceful disconnect handling for ASGI worker to properly handle
|
||
client disconnects without raising exceptions
|
||
([PR #3485](https://github.com/benoitc/gunicorn/pull/3485))
|
||
|
||
- Fix lazy import of dirty module for gevent compatibility - prevents
|
||
import errors when concurrent.futures is imported before gevent monkey-patching
|
||
([PR #3483](https://github.com/benoitc/gunicorn/pull/3483))
|
||
|
||
### Changes
|
||
|
||
- Refactor: Extract `_normalize_sockaddr` utility function for consistent
|
||
socket address handling across workers
|
||
|
||
- Add license headers to all Python source files
|
||
|
||
- Update copyright year to 2026 in LICENSE and NOTICE files
|
||
|
||
---
|
||
|
||
## 25.0.1 - 2026-02-02
|
||
|
||
### Bug Fixes
|
||
|
||
- Fix ASGI streaming responses (SSE) hanging: add chunked transfer encoding for
|
||
HTTP/1.1 responses without Content-Length header. Without chunked encoding,
|
||
clients wait for connection close to determine end-of-response.
|
||
|
||
### Changes
|
||
|
||
- Update celery_alternative example to use FastAPI with native ASGI worker and
|
||
uvloop for async task execution
|
||
|
||
### Testing
|
||
|
||
- Add ASGI compliance test suite with Docker-based integration tests covering HTTP,
|
||
WebSocket, streaming, lifespan, framework integration (Starlette, FastAPI),
|
||
HTTP/2, and concurrency scenarios
|
||
|
||
---
|
||
|
||
## 25.0.0 - 2026-02-01
|
||
|
||
### New Features
|
||
|
||
- **Dirty Arbiters**: Separate process pool for executing long-running, blocking
|
||
operations (AI model loading, heavy computation) without blocking HTTP workers
|
||
([PR #3460](https://github.com/benoitc/gunicorn/pull/3460))
|
||
- Inspired by Erlang's dirty schedulers
|
||
- Asyncio-based with Unix socket IPC
|
||
- Stateful workers that persist loaded resources
|
||
- New settings: `--dirty-app`, `--dirty-workers`, `--dirty-timeout`,
|
||
`--dirty-threads`, `--dirty-graceful-timeout`
|
||
- Lifecycle hooks: `on_dirty_starting`, `dirty_post_fork`,
|
||
`dirty_worker_init`, `dirty_worker_exit`
|
||
|
||
- **Per-App Worker Allocation for Dirty Arbiters**: Control how many dirty workers
|
||
load each app for memory optimization with heavy models
|
||
([PR #3473](https://github.com/benoitc/gunicorn/pull/3473))
|
||
- Set `workers` class attribute on DirtyApp (e.g., `workers = 2`)
|
||
- Or use config format `module:class:N` (e.g., `myapp:HeavyModel:2`)
|
||
- Requests automatically routed to workers with the target app
|
||
- New exception `DirtyNoWorkersAvailableError` for graceful error handling
|
||
- Example: 8 workers × 10GB model = 80GB → with `workers=2`: 20GB (75% savings)
|
||
|
||
- **HTTP/2 Support (Beta)**: Native HTTP/2 (RFC 7540) support for improved performance
|
||
with modern clients ([PR #3468](https://github.com/benoitc/gunicorn/pull/3468))
|
||
- Multiplexed streams over a single connection
|
||
- Header compression (HPACK)
|
||
- Flow control and stream prioritization
|
||
- Works with gthread, gevent, and ASGI workers
|
||
- New settings: `--http-protocols`, `--http2-max-concurrent-streams`,
|
||
`--http2-initial-window-size`, `--http2-max-frame-size`, `--http2-max-header-list-size`
|
||
- Requires SSL/TLS and h2 library: `pip install gunicorn[http2]`
|
||
- See [HTTP/2 Guide](guides/http2.md) for details
|
||
- New example: `examples/http2_gevent/` with Docker and tests
|
||
|
||
- **HTTP 103 Early Hints**: Support for RFC 8297 Early Hints to enable browsers to
|
||
preload resources before the final response
|
||
([PR #3468](https://github.com/benoitc/gunicorn/pull/3468))
|
||
- WSGI: `environ['wsgi.early_hints'](headers)` callback
|
||
- ASGI: `http.response.informational` message type
|
||
- Works with both HTTP/1.1 and HTTP/2
|
||
|
||
- **uWSGI Protocol for ASGI Worker**: The ASGI worker now supports receiving requests
|
||
via the uWSGI binary protocol from nginx
|
||
([PR #3467](https://github.com/benoitc/gunicorn/pull/3467))
|
||
|
||
### Bug Fixes
|
||
|
||
- Fix HTTP/2 ALPN negotiation for gevent and eventlet workers when
|
||
`do_handshake_on_connect` is False (the default). The TLS handshake is now
|
||
explicitly performed before checking `selected_alpn_protocol()`.
|
||
|
||
- Fix setproctitle initialization with systemd socket activation
|
||
([#3465](https://github.com/benoitc/gunicorn/issues/3465))
|
||
|
||
- Fix `Expect: 100-continue` handling: ignore the header for HTTP/1.0 requests
|
||
since 100-continue is only valid for HTTP/1.1+
|
||
([PR #3463](https://github.com/benoitc/gunicorn/pull/3463))
|
||
|
||
- Fix missing `_expected_100_continue` attribute in UWSGIRequest
|
||
|
||
- Disable setproctitle on macOS to prevent segfaults during process title updates
|
||
|
||
- Publish full exception traceback when the application fails to load
|
||
([#3462](https://github.com/benoitc/gunicorn/issues/3462))
|
||
|
||
### Deprecations
|
||
|
||
- **Eventlet Worker**: The `eventlet` worker is deprecated and will be removed in
|
||
Gunicorn 26.0. Eventlet itself is [no longer actively maintained](https://eventlet.readthedocs.io/en/latest/asyncio/migration.html).
|
||
Please migrate to `gevent`, `gthread`, or another supported worker type.
|
||
|
||
### Changes
|
||
|
||
- Remove obsolete Makefile targets
|
||
([PR #3471](https://github.com/benoitc/gunicorn/pull/3471))
|
||
|
||
---
|
||
|
||
## 24.1.1 - 2026-01-24
|
||
|
||
### Bug Fixes
|
||
|
||
- Fix `forwarded_allow_ips` and `proxy_allow_ips` to remain as strings for backward
|
||
compatibility with external tools like uvicorn. Network validation now uses strict
|
||
mode to detect invalid CIDR notation (e.g., `192.168.1.1/24` where host bits are set)
|
||
([#3458](https://github.com/benoitc/gunicorn/issues/3458),
|
||
[PR #3459](https://github.com/benoitc/gunicorn/pull/3459))
|
||
|
||
---
|
||
|
||
## 24.1.0 - 2026-01-23
|
||
|
||
### New Features
|
||
|
||
- **Official Docker Image**: Gunicorn now publishes official Docker images to GitHub
|
||
Container Registry at `ghcr.io/benoitc/gunicorn`
|
||
- Based on Python 3.12 slim image
|
||
- Uses recommended worker formula (2 × CPU + 1)
|
||
- Configurable via environment variables
|
||
|
||
- **PROXY Protocol v2 Support**: Extended PROXY protocol implementation to support
|
||
the binary v2 format in addition to the existing text-based v1 format
|
||
([PR #3451](https://github.com/benoitc/gunicorn/pull/3451))
|
||
- New `--proxy-protocol` modes: `off`, `v1`, `v2`, `auto`
|
||
- `auto` mode (default when enabled) detects v1 or v2 automatically
|
||
- v2 binary format is more efficient and supports additional metadata
|
||
- Works with HAProxy, AWS NLB/ALB, and other PROXY protocol v2 sources
|
||
|
||
- **CIDR Network Support**: `--forwarded-allow-ips` and `--proxy-allow-from` now
|
||
accept CIDR notation (e.g., `192.168.0.0/16`) for specifying trusted networks
|
||
([PR #3449](https://github.com/benoitc/gunicorn/pull/3449))
|
||
|
||
- **Socket Backlog Metric**: New `gunicorn.socket.backlog` gauge metric reports
|
||
the current socket backlog size on Linux systems
|
||
([PR #3450](https://github.com/benoitc/gunicorn/pull/3450))
|
||
|
||
- **InotifyReloader Enhancement**: The inotify-based reloader now watches newly
|
||
imported modules, not just those loaded at startup
|
||
([PR #3447](https://github.com/benoitc/gunicorn/pull/3447))
|
||
|
||
### Bug Fixes
|
||
|
||
- Fix signal handling regression where SIGCLD alias caused "Unhandled signal: cld"
|
||
errors on Linux when workers fail during boot
|
||
([#3453](https://github.com/benoitc/gunicorn/discussions/3453))
|
||
|
||
- Fix socket blocking mode on keepalive connections preventing SSL handshake
|
||
failures with async workers
|
||
([PR #3452](https://github.com/benoitc/gunicorn/pull/3452))
|
||
|
||
- Use smaller buffer size in `finish_body()` for faster timeout detection on
|
||
slow or abandoned connections
|
||
([PR #3453](https://github.com/benoitc/gunicorn/pull/3453))
|
||
|
||
- Handle `SSLWantReadError` in `finish_body()` to prevent worker hangs during
|
||
SSL renegotiation
|
||
([PR #3448](https://github.com/benoitc/gunicorn/pull/3448))
|
||
|
||
- Log SIGTERM as info level instead of warning to reduce noise in orchestrated
|
||
environments
|
||
([PR #3446](https://github.com/benoitc/gunicorn/pull/3446))
|
||
|
||
- Print exception details to stderr when worker fails to boot
|
||
([PR #3443](https://github.com/benoitc/gunicorn/pull/3443))
|
||
|
||
- Fix `unreader.unread()` to prepend data to buffer instead of appending
|
||
([PR #3442](https://github.com/benoitc/gunicorn/pull/3442))
|
||
|
||
- Prevent `RecursionError` when pickling Config objects
|
||
([PR #3441](https://github.com/benoitc/gunicorn/pull/3441))
|
||
|
||
- Use proper exception chaining with `raise from` in glogging.py
|
||
([PR #3440](https://github.com/benoitc/gunicorn/pull/3440))
|
||
|
||
---
|
||
|
||
## 24.0.0 - 2026-01-23
|
||
|
||
### New Features
|
||
|
||
- **ASGI Worker (Beta)**: Native asyncio-based ASGI support for running async Python
|
||
frameworks like FastAPI, Starlette, and Quart without external dependencies
|
||
([PR #3444](https://github.com/benoitc/gunicorn/pull/3444))
|
||
- HTTP/1.1 with keepalive connections
|
||
- WebSocket support
|
||
- Lifespan protocol for startup/shutdown hooks
|
||
- Optional uvloop for improved performance
|
||
- New settings: `--asgi-loop`, `--asgi-lifespan`, `--root-path`
|
||
|
||
- **uWSGI Binary Protocol**: Support for receiving requests from nginx via
|
||
`uwsgi_pass` directive, enabling efficient binary protocol communication
|
||
([PR #3444](https://github.com/benoitc/gunicorn/pull/3444))
|
||
- New settings: `--protocol uwsgi`, `--uwsgi-allow-from`
|
||
|
||
- **Documentation Migration**: Migrated documentation from Sphinx to MkDocs
|
||
with Material theme for improved navigation and mobile experience
|
||
([PR #3426](https://github.com/benoitc/gunicorn/pull/3426))
|
||
|
||
### Security
|
||
|
||
- **eventlet**: Require eventlet >= 0.40.3 to address CVE-2021-21419 (websocket
|
||
memory exhaustion) and CVE-2025-58068 (HTTP request smuggling)
|
||
([PR #3445](https://github.com/benoitc/gunicorn/pull/3445))
|
||
|
||
- **gevent**: Require gevent >= 24.10.1 to address CVE-2023-41419 (HTTP request
|
||
smuggling) and CVE-2024-3219 (socket.socketpair vulnerability)
|
||
([PR #3445](https://github.com/benoitc/gunicorn/pull/3445))
|
||
|
||
- **tornado**: Require tornado >= 6.5.0 to address CVE-2025-47287 (HTTP request
|
||
smuggling) and other security fixes
|
||
([PR #3445](https://github.com/benoitc/gunicorn/pull/3445))
|
||
|
||
### Changes
|
||
|
||
- Documentation now hosted at https://gunicorn.org
|
||
- Updated license configuration to PEP 639 format for uv compatibility
|
||
|
||
!!! warning "ASGI Worker Beta"
|
||
The ASGI worker is a beta feature. While tested, the API and behavior
|
||
may change in future releases. Please report any issues on GitHub.
|