3434 Commits

Author SHA1 Message Date
Benoit Chesneau
2d4310116d docs: merge gunicornc into 25.1.0 release 2026-02-13 12:03:48 +01:00
Benoit Chesneau
bf4ad8d610 docs: update 25.1.0 release date to 2026-02-13 2026-02-13 11:59:42 +01:00
Benoit Chesneau
730350eb9f
Merge pull request #3505 from benoitc/feature/gunicornc-control-interface
feat(ctl): add gunicornc control interface
2026-02-13 11:31:45 +01:00
Benoit Chesneau
63df19bd5c fix(tests): use process groups for reliable signal handling in PyPy
- Use preexec_fn=os.setsid to create new process group
- Send signals to process group with os.killpg() instead of single process
- Add explicit timeout and graceful-timeout to gunicorn command
- Fixes test failures on PyPy 3.10 where signals weren't propagating properly
2026-02-13 11:02:10 +01:00
Benoit Chesneau
cd77bcc941 fix(tests): increase wait time for all server tests 2026-02-13 10:48:41 +01:00
Benoit Chesneau
02ea9855c1 fix(tests): improve server test reliability on FreeBSD 2026-02-13 10:37:22 +01:00
Benoit Chesneau
6d81c9ebcd fix: resolve pylint warnings 2026-02-13 02:40:01 +01:00
Benoit Chesneau
7486baa0ad fix: remove unused imports 2026-02-13 02:35:02 +01:00
Benoit Chesneau
3e60d2942d docs: add gunicornc control interface guide
- Add guides/gunicornc.md with usage examples and command reference
- Update mkdocs.yml navigation to include Control Interface guide
- Update 2026-news.md and news.md changelog with 25.2.0 release
- Regenerate reference/settings.md with control socket settings
2026-02-13 02:29:44 +01:00
Benoit Chesneau
e05e40d19b feat(ctl): add message-based dirty worker management
Replace signal-based dirty add/remove with protocol messages:
- Add MSG_TYPE_MANAGE to dirty protocol for worker management
- Add MANAGE_OP_ADD and MANAGE_OP_REMOVE operation codes
- Add handle_manage_request() in DirtyArbiter
- Update handlers to send messages instead of SIGTTIN/SIGTTOU signals

New workers only load apps that haven't reached their worker limits.
When all apps are at their limits, returns reason in response.
Only increment num_workers when a worker is actually spawned.
2026-02-13 02:25:37 +01:00
Benoit Chesneau
7df260930c fix(ctl): use 'result' key from dirty protocol response
The dirty protocol response uses 'result' not 'data' for the payload.
2026-02-13 02:01:38 +01:00
Benoit Chesneau
be27ed4036 fix(ctl): properly encode/decode MSG_TYPE_STATUS for dirty worker query
- Add encode_status method to BinaryProtocol
- Use arbiter.dirty_arbiter.socket_path instead of env var when available
2026-02-13 01:56:39 +01:00
Benoit Chesneau
3e6d6b94c5 feat(ctl): query dirty arbiter for worker info in 'show all'
Add MSG_TYPE_STATUS to dirty protocol to allow querying the dirty
arbiter for its workers. The control socket now connects to the
dirty arbiter socket to retrieve worker information.
2026-02-13 01:52:43 +01:00
Benoit Chesneau
9f7000ff63 feat(ctl): add 'show all' command for process overview
Displays complete hierarchy: arbiter PID, web workers with their
PIDs/status, dirty arbiter PID, and dirty workers with their apps.
2026-02-13 01:47:45 +01:00
Benoit Chesneau
3963e850ea fix(dirty): reduce log verbosity for worker spawn skip
Change 'No apps need more workers' from warning to debug level
to avoid log spam when all apps have sufficient workers.
2026-02-13 01:44:35 +01:00
Benoit Chesneau
a57507c4e5 feat(ctl): add gunicornc control interface
Add a control socket server and CLI client for runtime management
of Gunicorn instances, similar to birdc for BIRD routing daemon.

Features:
- Control socket server running in arbiter process (asyncio/threaded)
- gunicornc CLI with interactive and single-command modes
- JSON protocol with length-prefixed framing
- Commands: show workers/stats/config/listeners/dirty, worker add/remove/kill,
  dirty add/remove, reload, reopen, shutdown
- Stats tracking (uptime, workers spawned/killed, reloads)
- Configurable socket path and permissions

New config options:
- control_socket: Unix socket path (default: gunicorn.ctl)
- control_socket_mode: Socket permissions (default: 0o600)
- --no-control-socket: Disable control socket
2026-02-13 01:38:17 +01:00
Benoit Chesneau
3cba17b84a
Merge pull request #3504 from benoitc/feature/dirty-ttin-ttou
feat(dirty): add TTIN/TTOU signal support for dynamic worker scaling
2026-02-13 00:17:31 +01:00
Benoit Chesneau
0077b05916 docs: add TTIN/TTOU to changelog 2026-02-12 23:59:20 +01:00
Benoit Chesneau
2639215aa3 feat(dirty): add TTIN/TTOU signal support for dynamic worker scaling
Add support for SIGTTIN and SIGTTOU signals to the dirty arbiter,
allowing dynamic scaling of dirty workers at runtime without restarting
gunicorn.

Changes:
- Add TTIN/TTOU to DirtyArbiter.SIGNALS
- Add num_workers instance variable for dynamic count
- Add _get_minimum_workers() to enforce app worker constraints
- Add signal handlers for TTIN (increase) and TTOU (decrease)
- Update manage_workers() to use dynamic count
- Add documentation for dynamic scaling
- Add unit tests for signal handling
- Add Docker integration tests

The minimum worker constraint ensures TTOU cannot reduce workers below
what apps require (e.g., if an app has workers=3, minimum is 3).

Closes #3489
2026-02-12 23:52:12 +01:00
Benoit Chesneau
ac00c862d7 docs: mark ASGI as stable, Dirty Arbiters as beta
- Remove beta warning from ASGI worker documentation
- Add beta warning to Dirty Arbiters documentation
- Update README feature list accordingly
- Update changelog to reflect stability changes
2026-02-12 22:09:14 +01:00
Benoit Chesneau
7f6cf908e5 release: 25.1.0
New Features:
- Dirty Stash: global shared state between workers (#3503)
- Dirty Binary Protocol: TLV encoding for efficient IPC (#3500)

Documentation:
- Fix Markdown formatting in /configure
2026-02-12 22:06:44 +01:00
Benoit Chesneau
709a6ad159
feat(dirty): add stash - global shared state between workers (#3503)
* feat(dirty): add stash - global shared state between workers

Add a simple key-value store (stash) that allows dirty workers to share
state through the arbiter. Tables are stored directly in arbiter memory
for fast access and simplicity.

Features:
- Auto-create tables on first access
- Dict-like interface via stash.table()
- Pattern matching for keys (glob patterns)
- Module-level API: stash.put(), stash.get(), stash.delete(), etc.

Usage:
    from gunicorn.dirty import stash

    stash.put("sessions", "user:1", {"name": "Alice"})
    user = stash.get("sessions", "user:1")

    # Or dict-like
    sessions = stash.table("sessions")
    sessions["user:1"] = {"name": "Alice"}

New files:
- gunicorn/dirty/stash.py - Client API and StashTable class
- Protocol additions for MSG_TYPE_STASH and STASH_OP_* codes

Note: Tables are ephemeral - lost if arbiter restarts.

* test(dirty): add tests for stash protocol and encoding

Test coverage for:
- Stash message creation and encoding
- Protocol constants (MSG_TYPE_STASH, STASH_OP_*)
- Error classes (StashError, StashTableNotFoundError, StashKeyNotFoundError)
- StashTable dict-like interface
- Edge cases: unicode, complex values, special patterns

* example(dirty): add stash usage example and integration tests

- Add SessionApp to dirty_app.py demonstrating stash usage
- Add /session/* endpoints to wsgi_app.py
- Add test_stash_integration.py with Docker tests
- Update docker-compose.yml with stash-test service
- Fix: Set GUNICORN_DIRTY_SOCKET in dirty arbiter for worker access

* docs(dirty): add stash documentation
2026-02-12 21:45:49 +01:00
Benoit Chesneau
236c9371d0
Merge pull request #3502 from Juneezee/docs/issues-3498
docs: fix Markdown formatting in /configure
2026-02-12 17:52:07 +01:00
Benoit Chesneau
4b90e4ba16
Merge pull request #3500 from benoitc/feature/binary-dirty-protocol
feat(dirty): implement binary protocol for dirty worker IPC
2026-02-12 17:26:10 +01:00
Eng Zer Jun
1cd4db8ddf
docs: fix Markdown formatting in /configure
Fixes https://github.com/benoitc/gunicorn/issues/3498.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2026-02-12 21:12:24 +08:00
Benoit Chesneau
415aa77343 fix: revert embedding_service port to 8000 for CI 2026-02-11 23:54:36 +01:00
Benoit Chesneau
f4e219716f fix(dirty): disable pylint too-many-return-statements in TLV 2026-02-11 23:48:07 +01:00
Benoit Chesneau
6d691b30e1 chore: use different ports in example docker-compose files
Avoid port conflicts when running multiple examples:
- dirty_example: 8001
- embedding_service: 8002
- celery_alternative: 8003
2026-02-11 23:40:10 +01:00
Benoit Chesneau
68ce658f5d fix(dirty): convert dict int keys to strings in TLV encoder
JSON serializes all dict keys as strings, so for compatibility the TLV
encoder should do the same. This fixes an error when tasks return dicts
with integer keys (e.g., aggregation results grouped by numeric ID).
2026-02-11 23:39:53 +01:00
Benoit Chesneau
c0cc8c0de0 test(dirty): add Docker setup for dirty example integration tests
- Add Dockerfile and docker-compose.yml for running examples in containers
- Add test_integration.py for HTTP-level integration testing
- Update test_worker_integration.py to use MockWriter for handle_request
- Use integer request IDs for binary protocol compatibility
- Add GUNICORN_BIND env var support in gunicorn_conf.py for Docker
2026-02-11 23:30:48 +01:00
Benoit Chesneau
00da70292f docs(dirty): update examples and docs for binary protocol
- Update test_protocol.py example to use binary protocol
- Add test_binary_data_handling example showing raw bytes transfer
- Update dirty.md to document binary TLV protocol format
- Replace JSON references with binary protocol
- Add Binary Protocol section with header and TLV encoding details
2026-02-11 23:15:14 +01:00
Benoit Chesneau
477b7479cc feat(dirty): update client for binary protocol
Update client and streaming tests to work with the binary protocol:
- Update MockStreamWriter/MockStreamReader to use BinaryProtocol
- Replace string request IDs with integers
- Update test assertions to decode binary protocol messages
- Use HEADER_SIZE and decode_header/decode_message instead of old API
2026-02-11 23:12:44 +01:00
Benoit Chesneau
98b1b649c2 feat(dirty): update arbiter for binary protocol
Update arbiter tests to work with the binary protocol:
- Update MockStreamWriter to decode binary messages
- Import binary protocol constants from module level
2026-02-11 23:03:40 +01:00
Benoit Chesneau
6d2139bb6c feat(dirty): update worker for binary protocol
Update worker tests to work with the binary protocol:
- Use integer request IDs instead of strings
- Update MockStreamWriter to decode binary messages
- Import binary protocol constants from module level
2026-02-11 23:01:21 +01:00
Benoit Chesneau
1665857c0e feat(dirty): implement binary protocol
Replace JSON-based protocol with binary format using 16-byte header:
- Magic bytes (GD), version, message type, payload length, request ID
- TLV-encoded payloads for efficient binary data transfer
- No base64 encoding needed for binary data
- Backwards compatible API (DirtyProtocol alias, dict-based interface)

Header format inspired by OpenBSD msgctl/msgsnd.
2026-02-11 22:58:43 +01:00
Benoit Chesneau
0e0dc669c8 feat(dirty): add TLV binary encoder/decoder
Implement TLV (Type-Length-Value) serialization layer for the binary
dirty worker protocol. This enables efficient binary data transfer
without base64 encoding overhead.

Supported types:
- None, bool, int64, float64
- bytes (raw binary, no encoding needed)
- string (UTF-8)
- list, dict (nested structures)

Inspired by OpenBSD msgctl/msgsnd message format.
2026-02-11 22:55:03 +01:00
Benoit Chesneau
fc850687df chore: prepare release 25.0.3 2026-02-07 15:36:43 +01:00
Benoit Chesneau
787602fc88 docs: shorten README sponsor section
Match homepage style and link to sponsor page for details.
2026-02-07 14:49:09 +01:00
Benoit Chesneau
a52c81ff3a
Merge pull request #3492 from benoitc/feature/improve-sponsorship
docs: improve sponsorship visibility
2026-02-07 14:45:53 +01:00
Benoit Chesneau
1afb2b7da9
Merge pull request #3490 from tyrossel/master
fix: passing maxsplit in re.split() as positional argument is deprecated
2026-02-07 14:45:05 +01:00
Benoit Chesneau
2ead70d7b3 docs: add Sponsor to top-level navigation
Make sponsor page more visible by adding it as a top-level nav item
after Community, while keeping it in Community submenu as well.
2026-02-07 14:07:53 +01:00
Benoit Chesneau
874e8be0a1 docs: shorten sponsor section on homepage
Simplify the sponsor section to a single concise line and link to
the dedicated sponsor page instead of GitHub sponsors directly.
2026-02-07 11:31:40 +01:00
Benoit Chesneau
7293b216f4 docs: add prominent sponsorship options
- Add sponsor banner at top of README
- Add Revolut and Open Collective to FUNDING.yml
- Add dedicated sponsor page in docs
- Add sponsor heart link in footer
2026-02-07 11:29:15 +01:00
Benoit Chesneau
70d571bd7c docs: update homepage title and remove version display
- Change title from "The Python WSGI Server" to "Serve Python Apps on the Web"
- Remove "Version {{ version }}" text from hero section
- Remove unused .hero__version CSS
2026-02-07 11:08:04 +01:00
Benoit Chesneau
d301d53758 fix: resolve RuntimeError when StopIteration raised in ASGI coroutine
In Python 3.7+, PEP 479 converts StopIteration raised inside coroutines
to RuntimeError. Changed _read_into() to raise NoMoreData instead, which
is already properly handled by the protocol layer.
2026-02-07 09:00:46 +01:00
Benoit Chesneau
9508df658d test: increase CI timeout for signal tests on PyPy 2026-02-06 09:00:29 +01:00
Tanguy Rossel
68abb98e4e
fix: passing maxsplit in re.split() as positional argument is deprecated 2026-02-06 08:42:32 +01:00
Benoit Chesneau
2c0f9593a4 fix: remove trailing blank line in instrument/__init__.py 2026-02-06 08:36:35 +01:00
Benoit Chesneau
95b7ffeeaa chore: prepare release 25.0.2
- 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
2026-02-06 08:21:18 +01:00
Benoit Chesneau
026167acc9 refactor: extract _normalize_sockaddr utility function
Consolidate the repeated pattern for normalizing socket addresses
to ASGI-compatible (host, port) tuples into a single utility function.
2026-02-06 02:57:04 +01:00