使用start-stop-daemon将Django服务化时多PID无法完全停止求助
Hey there, let's tackle this issue where your Django service leaves leftover processes even after running the stop command. The multiple PIDs you're seeing are almost certainly child processes spawned by either the virtualenv wrapper, Django's runserver (especially if auto-reload is enabled), or a subshell created by your init script. Here's how to fix it:
1. Kill the Entire Process Group Instead of a Single PID
Most of the time, those extra PIDs are part of the same process group as the main PID in your $PIDFILE. Instead of just killing the single PID, you can kill the entire group to stop all related processes at once.
Update the stop section of your /etc/init.d/initfile script to use this approach:
stop() { if [ -f $PIDFILE ]; then PID=$(cat $PIDFILE) # Kill the entire process group (note the negative sign before PID) if kill -- -$PID 2>/dev/null; then echo "Successfully stopped Django service and all child processes" rm -f $PIDFILE else echo "Service might not be running, or failed to stop all processes" fi else echo "PID file $PIDFILE doesn't exist - service isn't running" fi }
The kill -- -$PID syntax sends a signal to every process in the group led by $PID, ensuring no child processes are left behind.
2. Avoid Spawning Subshells in Your Startup Command
If your init script uses shell features like pipes, &, or nested commands, it might create extra subshell processes that aren't tied to the main PID. Use exec to replace the current shell with your Django process, which eliminates subshells:
Modify your startup command to look something like this:
start() { # Activate virtualenv and exec the Django runserver directly cd /path/to/your/django/project exec $VIRTUAL_ENV/bin/python manage.py runserver 0.0.0.0:8000 > /var/log/django.log 2>&1 & echo $! > $PIDFILE echo "Django service started with PID $(cat $PIDFILE)" }
Using exec ensures the main process is the Django runserver itself, so the PID in $PIDFILE is the root of the process tree.
3. Verify Process Relationships First
To confirm exactly which processes are tied to your service, run this command with the main PID from your $PIDFILE:
pstree -p 22875
This will show you the full tree of parent and child processes. You'll see exactly how the extra PIDs (22878, 22880) are linked to the main process, which can help you fine-tune your stop logic.
4. Fallback: Use pkill to Match Process Command Lines
If the process group method doesn't work for some reason, you can use pkill to target all processes running your Django runserver command:
pkill -f "python /path/to/your/django/project/manage.py runserver"
Just make sure the command string is specific enough to avoid killing unrelated Python processes. Add this to your stop function as a backup if needed.
Test your updated script by starting the service, checking the PIDs with ps -fu root, then running the stop command and verifying all related processes are gone with ps -fu root | grep django.
内容的提问来源于stack exchange,提问作者rishardcarranza

