Is there a way to kill uvicorn cleanly?
Question:
Is there a way to kill uvicorn cleanly?
I.e., I can type ^C at it, if it is running in the foreground on a terminal. This causes the uvivorn process to die and all of the worker processes to be cleaned up. (I.e., they go away.)
On the other hand, if uvicorn is running in the background without a terminal, then I can’t figure out a way to kill it cleanly. It seems to ignore SIGTERM, SIGINT, and SIGHUP. I can kill it with SIGKILL (i.e. -9), but then the worker processes remain alive, and I have to track all the worker processes down and kill them too. This is not ideal.
I am using uvicorn with CPython 3.7.4, uvivorn version 0.11.2, and FastAPI 0.46.0 on Red Hat Enterprise Linux Server 7.3 (Maipo).
Answers:
That’s because you’re running uvicorn
as your only server. uvicorn
is not a process manager and, as so, it does not manage its workers life cycle. That’s why they recommend running uvicorn using gunicorn+UvicornWorker for production.
That said, you can kill the spawned workers and trigger it’s shutdown using the script below:
$ kill $(pgrep -P $uvicorn_pid)
The reason why this works but not the kill
on the parent pid is because when you ^C
something, the signal is transmitted throughout all of its spawned processes that are attached to the stdin
.
In my case uvicorn
managed to spawn new processes while pgrep -P
was killing old ones,
so I decided to kill the whole process group at once, just like ^C
does:
PID="$(pgrep -f example:app)"
if [[ -n "$PID" ]]
then
PGID="$(ps --no-headers -p $PID -o pgid)"
kill -SIGINT -- -${PGID// /}
fi
Each line explained:
pgrep -f example:app
gets the PID of the parent uvicorn ... example:app
[[ -n "$PID" ]]
checks this PID is not empty, to avoid further steps when uvicorn
is not running
ps --no-headers -p $PID -o pgid
gets PGID (Process Group ID) this PID is part of
kill -SIGINT
is similar to polite ^C
(you may use kill -9
for non-polite instant kill)
--
means the next token is a positional argument, not a named option, even if it starts with -
-${PGID
– negative value lets kill
know it is PGID, not PID
${PGID// /}
removes all spaces ps
added to PGID to align a column
lsof -i :8000
This will check processes using port :8000. If you are using different port for fastAPI then change the port number. I was using postman and python for fastAPI. So check process with python, then copy the PID usually 4-5 numbers.
Then run
kill -9 PID
Where PID is the PID number you copied
Your can try running below command
kill -9 $(ps -ef | grep uvicorn | awk '{print $2}')
or
Create and Alias with the command and keep using that command.
For example:
alias uvicornprocess="kill -9 $(ps -ef | grep uvicorn | awk '{print $2}')"
Is there a way to kill uvicorn cleanly?
I.e., I can type ^C at it, if it is running in the foreground on a terminal. This causes the uvivorn process to die and all of the worker processes to be cleaned up. (I.e., they go away.)
On the other hand, if uvicorn is running in the background without a terminal, then I can’t figure out a way to kill it cleanly. It seems to ignore SIGTERM, SIGINT, and SIGHUP. I can kill it with SIGKILL (i.e. -9), but then the worker processes remain alive, and I have to track all the worker processes down and kill them too. This is not ideal.
I am using uvicorn with CPython 3.7.4, uvivorn version 0.11.2, and FastAPI 0.46.0 on Red Hat Enterprise Linux Server 7.3 (Maipo).
That’s because you’re running uvicorn
as your only server. uvicorn
is not a process manager and, as so, it does not manage its workers life cycle. That’s why they recommend running uvicorn using gunicorn+UvicornWorker for production.
That said, you can kill the spawned workers and trigger it’s shutdown using the script below:
$ kill $(pgrep -P $uvicorn_pid)
The reason why this works but not the kill
on the parent pid is because when you ^C
something, the signal is transmitted throughout all of its spawned processes that are attached to the stdin
.
In my case uvicorn
managed to spawn new processes while pgrep -P
was killing old ones,
so I decided to kill the whole process group at once, just like ^C
does:
PID="$(pgrep -f example:app)"
if [[ -n "$PID" ]]
then
PGID="$(ps --no-headers -p $PID -o pgid)"
kill -SIGINT -- -${PGID// /}
fi
Each line explained:
pgrep -f example:app
gets the PID of the parentuvicorn ... example:app
[[ -n "$PID" ]]
checks this PID is not empty, to avoid further steps whenuvicorn
is not runningps --no-headers -p $PID -o pgid
gets PGID (Process Group ID) this PID is part ofkill -SIGINT
is similar to polite^C
(you may usekill -9
for non-polite instant kill)--
means the next token is a positional argument, not a named option, even if it starts with-
-${PGID
– negative value letskill
know it is PGID, not PID${PGID// /}
removes all spacesps
added to PGID to align a column
lsof -i :8000
This will check processes using port :8000. If you are using different port for fastAPI then change the port number. I was using postman and python for fastAPI. So check process with python, then copy the PID usually 4-5 numbers.
Then run
kill -9 PID
Where PID is the PID number you copied
Your can try running below command
kill -9 $(ps -ef | grep uvicorn | awk '{print $2}')
or
Create and Alias with the command and keep using that command.
For example:
alias uvicornprocess="kill -9 $(ps -ef | grep uvicorn | awk '{print $2}')"