3408 Commits

Author SHA1 Message Date
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
Benoit Chesneau
e780508f56 fix: resolve ASGI concurrent request failures through nginx proxy
- Fix nginx config to use keepalive with upstream (was sending
  Connection: close which caused premature connection closure)
- Add _safe_write() to handle socket errors (EPIPE, ECONNRESET,
  ENOTCONN) gracefully when client disconnects
- Fix ASGI scope server/client to always be 2-tuples for IPv6
  compatibility (IPv6 sockets return 4-tuples)
- Add write_eof() before close() to ensure buffered data is flushed
- Bind to [::] for dual-stack IPv4/IPv6 support in test containers
2026-02-06 01:57:28 +01:00
Benoit Chesneau
866e88cfd6
Merge pull request #3485 from benoitc/fix/asgi-graceful-disconnect
fix: graceful disconnect handling for ASGI worker
2026-02-03 09:30:19 +01:00
Benoit Chesneau
3bf718ea52 fix: graceful disconnect handling for ASGI worker
Closes #3484

When a client disconnects during an ASGI request, the worker now:
1. Sends http.disconnect message to the app's receive queue
2. Allows a configurable grace period for cleanup (default: 3 seconds)
3. Only cancels the task after the grace period expires

This follows the ASGI HTTP Connection Scope spec which defines
http.disconnect as the message apps should receive when clients
disconnect: https://asgi.readthedocs.io/en/latest/specs/www.html#disconnect-receive-event

The grace period prevents CancelledError from propagating to async
database operations, allowing SQLAlchemy and other async DB libraries
to properly reset their connection pools.

New config option: --asgi-disconnect-grace-period (default: 3 seconds)
2026-02-03 02:46:07 +01:00
Benoit Chesneau
15cadf87a7
Merge pull request #3483 from benoitc/fix/gevent-concurrent-futures-import
fix: lazy import dirty module for gevent compatibility
2026-02-03 01:33:32 +01:00
Benoit Chesneau
b19c648a67 fix: lazy import dirty module for gevent compatibility
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.
2026-02-03 01:15:39 +01:00
Benoit Chesneau
3373e4b987 docs: add CNAME file for custom domain 2026-02-02 23:36:30 +01:00
Benoit Chesneau
a7e14e16fd docs: replace sponsors section with expanded support section
Update README.md and docs homepage with detailed support messaging
including sponsorship benefits and corporate contact information.
2026-02-02 21:49:15 +01:00
Benoit Chesneau
3bf529f6c2 docs: sync news.md with 2026-news.md 2026-02-02 14:28:37 +01:00
Benoit Chesneau
1f4f245d76
Merge pull request #3478 from benoitc/feature/asgi-compliance-testbed
Add ASGI compliance test suite
2026-02-02 14:20:52 +01:00
Benoit Chesneau
e1519c0569 docs: add ASGI compliance test suite to changelog 2026-02-02 14:11:22 +01:00
Benoit Chesneau
0885005b08 fix(tests): correct assertions in ASGI compliance tests
- Fix path expectation in test_scope_path_preserved (router strips /http prefix)
- Fix lifespan state check to use scope_state instead of module_state
- Add tolerance for partial failures in proxy concurrent test
- Add retry logic with proper assertions in HTTPS proxy FastAPI test
2026-02-02 14:04:26 +01:00
Benoit Chesneau
658924c436 docs: update changelog for 25.0.1 2026-02-02 10:17:50 +01:00
Benoit Chesneau
c5b6e82277 chore: bump version to 25.0.1 2026-02-02 10:16:07 +01:00
Benoit Chesneau
ce352dc230 fix(asgi): add chunked transfer encoding for streaming responses
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.
2026-02-02 10:13:33 +01:00
Benoit Chesneau
29b8a3a763
Merge pull request #3476 from benoitc/dependabot/github_actions/actions/checkout-6
chore(deps): bump actions/checkout from 4 to 6
2026-02-02 00:47:56 +01:00
dependabot[bot]
791ab46e1c
chore(deps): bump actions/checkout from 4 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 23:47:36 +00:00
Benoit Chesneau
9235b72ab8
Merge pull request #3475 from benoitc/dependabot/github_actions/actions/upload-artifact-6
chore(deps): bump actions/upload-artifact from 4 to 6
2026-02-02 00:47:05 +01:00
Benoit Chesneau
26674b2ee8
Merge pull request #3474 from benoitc/dependabot/github_actions/actions/setup-python-6
chore(deps): bump actions/setup-python from 5 to 6
2026-02-02 00:46:36 +01:00
dependabot[bot]
0d8c3abe17
chore(deps): bump actions/upload-artifact from 4 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 21:42:44 +00:00
dependabot[bot]
772e4a250b
chore(deps): bump actions/setup-python from 5 to 6
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 21:42:41 +00:00
Benoit Chesneau
be54850ff8 docs: rename example title to Celery Alternative 2026-02-01 16:54:22 +01:00
Benoit Chesneau
17ac6a5254 examples: add celery_alternative example using dirty arbiters
Demonstrates replacing Celery with Gunicorn's dirty arbiters for
background task processing. Includes:

- 4 task workers: Email, Image, Data, Scheduled
- Stateful workers with persistent connections/caches
- Streaming progress for long-running tasks
- Per-app worker allocation
- Flask API with 15+ endpoints
- Docker deployment (single container vs Celery's 4+)
- Unit tests (19 tests) and integration tests
- Migration guide from Celery
2026-02-01 16:51:48 +01:00
Benoit Chesneau
9ece4a6873 docs: add GitHub icon to header, remove header.autohide 2026-02-01 15:04:41 +01:00
Benoit Chesneau
8652aec783 docs: update news.md with complete 25.0.0 changelog 2026-02-01 14:50:02 +01:00
Benoit Chesneau
d621aa81f9 fix: add version number to homepage hero section 2026-02-01 14:47:48 +01:00
Benoit Chesneau
617a85ea91 docs: update 25.0.0 release date to 2026-02-01 2026-02-01 14:30:56 +01:00