Revert "fix(wsgi): ensure gevent monkey-patching before Django import chain"

This commit is contained in:
SergeantPanda 2026-03-03 15:33:55 -06:00 committed by GitHub
parent 7da7ba97a9
commit d487bb5671
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 0 additions and 55 deletions

View file

@ -13,7 +13,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Celery Redis connections using unpatched sockets under gevent: `dispatcharr/__init__.py` imports `celery.py` as part of `django.setup()`, initialising the Redis connection pool before uWSGI's gevent plugin patches stdlib sockets. Added `gevent.monkey.patch_all()` at the top of `wsgi.py` to guarantee all broker connections are gevent-aware. - Thanks [@endoze](https://github.com/endoze)
- TS proxy streams dying after 30200 seconds in multi-worker uWSGI/Celery deployments, caused by three interrelated bugs. (Fixes #992, #980) - Thanks [@PFalko](https://github.com/PFalko)
- **Double ProxyServer instantiation**: `ProxyConfig.ready()` called `TSProxyServer()` directly while `TSProxyConfig.ready()` also called `TSProxyServer.get_instance()`, creating two instances per worker — each with its own cleanup thread. The orphaned thread could not extend ownership because it had no entries in `stream_managers`. Fixed by using `TSProxyServer.get_instance()` in `ProxyConfig.ready()`.
- **`flushdb()` on every Redis client init**: `RedisClient.get_client()` called `client.flushdb()` whenever `_client` was `None`. Celery autoscale (`--autoscale=6,1`) spawning new workers mid-stream triggered this path, nuking all Redis keys including active ownership keys, client records, and channel metadata. Removed the `flushdb()` call entirely.

View file

@ -1,39 +0,0 @@
"""Tests for dispatcharr/wsgi.py gevent monkey-patching."""
import os
import subprocess
import sys
import unittest
class TestWSGIGeventPatching(unittest.TestCase):
"""Verify that wsgi.py applies gevent monkey-patching before Django imports.
These tests run in subprocesses because monkey.patch_all() must execute
before any other imports. By the time Django's test runner loads this
file, ssl/socket are already imported, so calling patch_all() in-process
would fail. A subprocess mirrors how uWSGI actually loads wsgi.py.
"""
def test_socket_is_patched_after_wsgi_import(self):
"""Loading wsgi.py first (as uWSGI does) should patch sockets."""
result = subprocess.run(
[
sys.executable, "-c",
"import dispatcharr.wsgi; "
"from gevent import monkey; "
"assert monkey.is_module_patched('socket'), "
"'socket module was not patched by wsgi.py'; "
"print('PASS')",
],
capture_output=True,
text=True,
env={**os.environ, "DJANGO_SETTINGS_MODULE": "dispatcharr.settings"},
timeout=60,
cwd="/app",
)
self.assertEqual(
result.returncode,
0,
f"monkey-patching check failed:\n{result.stderr}",
)

View file

@ -1,21 +1,6 @@
"""
WSGI config for dispatcharr project.
"""
# When running under uWSGI with gevent, ensure monkey-patching is fully
# applied before any other imports. Django's setup triggers the import of
# dispatcharr/__init__.py → celery.py, which initialises the Celery broker
# transport. If those imports happen before sockets are patched, Celery's
# Redis connection pool holds unpatched sockets that silently fail under
# gevent's cooperative scheduling. Calling patch_all() here—before the
# Django import chain—guarantees every socket (including pooled broker
# connections) is gevent-aware. The call is idempotent, so it's harmless
# if uWSGI's gevent plugin has already patched.
try:
from gevent import monkey
monkey.patch_all()
except ImportError:
pass
import os
from django.core.wsgi import get_wsgi_application