forked from Mirrors/Dispatcharr
Remote debugging initial commit.
This commit is contained in:
parent
9ab76c3129
commit
1fcedab1ab
8 changed files with 254 additions and 8 deletions
|
|
@ -1,5 +1,6 @@
|
|||
**/__pycache__
|
||||
**/.venv
|
||||
**/venv
|
||||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
|
|
|
|||
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
|||
.DS_Store
|
||||
**/__pycache__/
|
||||
**/.vscode/
|
||||
**/venv
|
||||
*.pyc
|
||||
node_modules/
|
||||
.history/
|
||||
|
|
@ -10,4 +11,10 @@ docker/Dockerfile DEV
|
|||
static/
|
||||
data/
|
||||
.next
|
||||
next-env.d.ts
|
||||
next-env.d.ts
|
||||
media/
|
||||
celerybeat-schedule*
|
||||
dump.rdb
|
||||
debugpy*
|
||||
uwsgi.sock
|
||||
package-lock.json
|
||||
19
docker/docker-compose.debug.yml
Normal file
19
docker/docker-compose.debug.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
services:
|
||||
dispatcharr:
|
||||
# build:
|
||||
# context: ..
|
||||
# dockerfile: docker/Dockerfile.dev
|
||||
image: dispatcharr/dispatcharr
|
||||
container_name: dispatcharr_debug
|
||||
ports:
|
||||
- 5656:5656 # API port
|
||||
- 9193:9191 # Web UI port
|
||||
- 8001:8001 # Socket port
|
||||
- 5678:5678 # Debugging port
|
||||
volumes:
|
||||
- ../:/app
|
||||
environment:
|
||||
- DISPATCHARR_ENV=dev
|
||||
- DISPATCHARR_DEBUG=true
|
||||
- REDIS_HOST=localhost
|
||||
- CELERY_BROKER_URL=redis://localhost:6379/0
|
||||
|
|
@ -49,6 +49,7 @@ if [[ ! -f /etc/profile.d/dispatcharr.sh ]]; then
|
|||
echo "export POSTGRES_HOST=$POSTGRES_HOST" >> /etc/profile.d/dispatcharr.sh
|
||||
echo "export POSTGRES_PORT=$POSTGRES_PORT" >> /etc/profile.d/dispatcharr.sh
|
||||
echo "export DISPATCHARR_ENV=$DISPATCHARR_ENV" >> /etc/profile.d/dispatcharr.sh
|
||||
echo "export DISPATCHARR_DEBUG=$DISPATCHARR_DEBUG" >> /etc/profile.d/dispatcharr.sh
|
||||
echo "export REDIS_HOST=$REDIS_HOST" >> /etc/profile.d/dispatcharr.sh
|
||||
echo "export REDIS_DB=$REDIS_DB" >> /etc/profile.d/dispatcharr.sh
|
||||
fi
|
||||
|
|
@ -75,8 +76,18 @@ postgres_pid=$(su - postgres -c "/usr/lib/postgresql/14/bin/pg_ctl -D /data stat
|
|||
echo "✅ Postgres started with PID $postgres_pid"
|
||||
pids+=("$postgres_pid")
|
||||
|
||||
if [ "$DISPATCHARR_ENV" = "dev" ]; then
|
||||
|
||||
uwsgi_file="/app/docker/uwsgi.ini"
|
||||
if [ "$DISPATCHARR_ENV" = "dev" ] && [ "$DISPATCHARR_DEBUG" != "true" ]; then
|
||||
uwsgi_file="/app/docker/uwsgi.dev.ini"
|
||||
elif [ "$DISPATCHARR_DEBUG" = "true" ]; then
|
||||
uwsgi_file="/app/docker/uwsgi.debug.ini"
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$DISPATCHARR_ENV" = "dev" ]]; then
|
||||
. /app/docker/init/99-init-dev.sh
|
||||
|
||||
else
|
||||
echo "🚀 Starting nginx..."
|
||||
nginx
|
||||
|
|
@ -85,10 +96,6 @@ else
|
|||
pids+=("$nginx_pid")
|
||||
fi
|
||||
|
||||
uwsgi_file="/app/docker/uwsgi.ini"
|
||||
if [ "$DISPATCHARR_ENV" = "dev" ]; then
|
||||
uwsgi_file="/app/docker/uwsgi.dev.ini"
|
||||
fi
|
||||
|
||||
echo "🚀 Starting uwsgi..."
|
||||
su - $POSTGRES_USER -c "cd /app && uwsgi --ini $uwsgi_file &"
|
||||
|
|
@ -97,7 +104,6 @@ echo "✅ uwsgi started with PID $uwsgi_pid"
|
|||
pids+=("$uwsgi_pid")
|
||||
|
||||
|
||||
|
||||
cd /app
|
||||
python manage.py migrate --noinput
|
||||
python manage.py collectstatic --noinput
|
||||
|
|
|
|||
|
|
@ -15,5 +15,11 @@ fi
|
|||
|
||||
# Install frontend dependencies
|
||||
cd /app/frontend && npm install
|
||||
|
||||
# Install pip dependencies
|
||||
cd /app && pip install -r requirements.txt
|
||||
|
||||
# Install debugpy for remote debugging
|
||||
if [ "$DISPATCHARR_DEBUG" = "true" ]; then
|
||||
echo "=== setting up debugpy ==="
|
||||
pip install debugpy
|
||||
fi
|
||||
|
|
|
|||
81
docker/uwsgi.debug.ini
Normal file
81
docker/uwsgi.debug.ini
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
[uwsgi]
|
||||
; exec-before = python manage.py collectstatic --noinput
|
||||
; exec-before = python manage.py migrate --noinput
|
||||
|
||||
; First run Redis availability check script once
|
||||
exec-before = python /app/scripts/wait_for_redis.py
|
||||
|
||||
; Start Redis first
|
||||
attach-daemon = redis-server
|
||||
; Then start other services
|
||||
attach-daemon = celery -A dispatcharr worker -l info
|
||||
attach-daemon = celery -A dispatcharr beat -l info
|
||||
attach-daemon = daphne -b 0.0.0.0 -p 8001 dispatcharr.asgi:application
|
||||
attach-daemon = cd /app/frontend && npm run dev
|
||||
|
||||
# Core settings
|
||||
chdir = /app
|
||||
module = scripts.debug_wrapper:application
|
||||
virtualenv = /dispatcharrpy
|
||||
master = true
|
||||
env = DJANGO_SETTINGS_MODULE=dispatcharr.settings
|
||||
socket = /app/uwsgi.sock
|
||||
chmod-socket = 777
|
||||
vacuum = true
|
||||
die-on-term = true
|
||||
static-map = /static=/app/static
|
||||
|
||||
# Worker configuration
|
||||
workers = 1
|
||||
threads = 4
|
||||
enable-threads = true
|
||||
lazy-apps = true
|
||||
|
||||
# HTTP server
|
||||
http = 0.0.0.0:5656
|
||||
http-keepalive = 1
|
||||
buffer-size = 65536
|
||||
http-timeout = 600
|
||||
|
||||
# Async mode (use gevent for high concurrency)
|
||||
gevent = 100
|
||||
async = 100
|
||||
|
||||
# Performance tuning
|
||||
thunder-lock = true
|
||||
log-4xx = true
|
||||
log-5xx = true
|
||||
disable-logging = false
|
||||
|
||||
; Longer timeouts for debugging sessions
|
||||
harakiri = 3600
|
||||
socket-timeout = 3600
|
||||
http-timeout = 3600
|
||||
|
||||
|
||||
# Ignore unknown options
|
||||
ignore-sigpipe = true
|
||||
ignore-write-errors = true
|
||||
disable-write-exception = true
|
||||
|
||||
# Explicitly disable for-server option that confuses debugpy
|
||||
for-server = false
|
||||
|
||||
# Debugging settings
|
||||
py-autoreload = 1
|
||||
honour-stdin = true
|
||||
|
||||
# Environment variables
|
||||
env = PYTHONPATH=/app
|
||||
env = PYTHONUNBUFFERED=1
|
||||
env = PYDEVD_DISABLE_FILE_VALIDATION=1
|
||||
env = PYTHONUTF8=1
|
||||
env = PYTHONXOPT=-Xfrozen_modules=off
|
||||
env = PYDEVD_DEBUG=1
|
||||
env = DEBUGPY_LOG_DIR=/app/debugpy_logs
|
||||
|
||||
# Debugging control variables
|
||||
env = WAIT_FOR_DEBUGGER=false
|
||||
env = DEBUG_TIMEOUT=30
|
||||
|
||||
|
||||
90
scripts/debug_wrapper.py
Normal file
90
scripts/debug_wrapper.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""
|
||||
Debug wrapper for the WSGI application.
|
||||
This module initializes debugpy and then imports the actual application.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import inspect
|
||||
|
||||
# Configure logging to output to both console and file
|
||||
os.makedirs('/app/debugpy_logs', exist_ok=True)
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s [%(levelname)s] %(name)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler('/app/debugpy_logs/debug_wrapper.log'),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger('debug_wrapper')
|
||||
|
||||
# Log system info
|
||||
logger.info(f"Python version: {sys.version}")
|
||||
logger.info(f"Current directory: {os.getcwd()}")
|
||||
logger.info(f"Files in current directory: {os.listdir()}")
|
||||
logger.info(f"Python path: {sys.path}")
|
||||
|
||||
# Default timeout in seconds
|
||||
DEBUG_TIMEOUT = int(os.environ.get('DEBUG_TIMEOUT', '30'))
|
||||
# Whether to wait for debugger to attach
|
||||
WAIT_FOR_DEBUGGER = os.environ.get('WAIT_FOR_DEBUGGER', 'false').lower() == 'true'
|
||||
|
||||
logger.info(f"DEBUG_TIMEOUT: {DEBUG_TIMEOUT}")
|
||||
logger.info(f"WAIT_FOR_DEBUGGER: {WAIT_FOR_DEBUGGER}")
|
||||
|
||||
try:
|
||||
import debugpy
|
||||
from debugpy import configure
|
||||
logger.info("Successfully imported debugpy")
|
||||
|
||||
# Critical: Configure debugpy to use regular Python for the adapter, not uwsgi
|
||||
python_path = '/usr/local/bin/python3'
|
||||
if os.path.exists(python_path):
|
||||
logger.info(f"Setting debugpy adapter to use Python interpreter: {python_path}")
|
||||
debugpy.configure(python=python_path)
|
||||
else:
|
||||
logger.warning(f"Python path {python_path} not found. Using system default.")
|
||||
|
||||
# Don't wait for connection, just set up the debugging session
|
||||
logger.info("Initializing debugpy on 0.0.0.0:5678...")
|
||||
try:
|
||||
# Use connect instead of listen to avoid the adapter process
|
||||
debugpy.listen(("0.0.0.0", 5678))
|
||||
logger.info("debugpy now listening on 0.0.0.0:5678")
|
||||
|
||||
if WAIT_FOR_DEBUGGER:
|
||||
logger.info(f"Waiting for debugger to attach (timeout: {DEBUG_TIMEOUT}s)...")
|
||||
start_time = time.time()
|
||||
while not debugpy.is_client_connected() and (time.time() - start_time < DEBUG_TIMEOUT):
|
||||
time.sleep(1)
|
||||
logger.info("Waiting for debugger connection...")
|
||||
|
||||
if debugpy.is_client_connected():
|
||||
logger.info("Debugger attached!")
|
||||
else:
|
||||
logger.info(f"Debugger not attached after {DEBUG_TIMEOUT}s, continuing anyway...")
|
||||
except Exception as e:
|
||||
logger.error(f"Error with debugpy.listen: {e}", exc_info=True)
|
||||
logger.info("Continuing without debugging...")
|
||||
|
||||
except ImportError:
|
||||
logger.error("debugpy not installed, continuing without debugging support")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize debugpy: {e}", exc_info=True)
|
||||
logger.info("Continuing without debugging support")
|
||||
|
||||
# Now import the actual WSGI application
|
||||
logger.info("Loading WSGI application...")
|
||||
try:
|
||||
from dispatcharr.wsgi import application
|
||||
logger.info("WSGI application loaded successfully")
|
||||
|
||||
# Log the application details
|
||||
logger.info(f"Application type: {type(application)}")
|
||||
logger.info(f"Application callable: {inspect.isfunction(application) or inspect.ismethod(application)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading WSGI application: {e}", exc_info=True)
|
||||
raise
|
||||
36
scripts/standalone_debug.py
Normal file
36
scripts/standalone_debug.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"""
|
||||
Standalone debug entry point for the Django application.
|
||||
This provides a cleaner way to debug without uWSGI complications.
|
||||
|
||||
Run this directly with Python to debug:
|
||||
python standalone_debug.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import debugpy
|
||||
import logging
|
||||
|
||||
# Configure basic logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s [%(levelname)s] %(name)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger('standalone_debug')
|
||||
|
||||
# Setup Django environment
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dispatcharr.settings')
|
||||
|
||||
# Setup debugpy and wait for connection
|
||||
logger.info("Setting up debugpy...")
|
||||
debugpy.listen(("0.0.0.0", 5678))
|
||||
logger.info("Waiting for debugger to attach... Connect to 0.0.0.0:5678")
|
||||
debugpy.wait_for_client()
|
||||
logger.info("Debugger attached!")
|
||||
|
||||
# Import Django and run the development server
|
||||
logger.info("Starting Django development server...")
|
||||
import django
|
||||
django.setup()
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
execute_from_command_line(['manage.py', 'runserver', '0.0.0.0:8000'])
|
||||
Loading…
Add table
Add a link
Reference in a new issue