30

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).

Douglas
  • 2,555
  • 3
  • 24
  • 30
  • Might be related to #364, could you explain how to run it in the background without a terminal so that I can have a look at it? sigterm and sigint are the only 2 that are "listened" at – euri10 Feb 27 '20 at 05:21
  • @euri10 There are many ways to run uvicorn in the background without a terminal. One way is to run it, and then to type ^Z to pause it. And then type "bg" to continue it in the background. And then type "exit" to the shell to make the shell and terminal go away. Alternatively, you could initially run it with "&" on the end of the command line, and elide the ^Z and the "bg". (You still need to type "exit" to the shell to make the shell and terminal go away.) – Douglas Feb 27 '20 at 20:00
  • @euri10 P.S Thanks for looking into this! – Douglas Feb 27 '20 at 21:31
  • just tested and I cant reproduce, in a terminal I run uvicorn example:app &! (I'm using zsh so have to use the ! to disown the process or I cant exit the terminal having running jobs) then I close the terminal and I kill -15 pidof uvicorn and it's gone, if you have a way to reproduce happy to try – euri10 Feb 28 '20 at 07:54
  • Hmmm, weird! Sometimes things behave differently under different shells, but I can't install zsh easily on the computer in question. It could be a problem specific to Red Hat for some reason, but I wouldn't be able to reproduce that without giving you a Docker image, or something. Or it might be an issue with specific versions of things that I am running. But I can't easily change those either for various reasons. In any case, thanks for looking into this! – Douglas Feb 28 '20 at 17:55
  • How do you run your uvicorn? Are you using uvicornWorkers with gunicorn or pure uvicorn? – Yagiz Degirmenci Jul 16 '20 at 12:39
  • I run it like so: (cd /home/foo; anaconda3-2019.10/bin/uvicorn --workers 20 --port 6700 en_pam_gb:app &> LOG.txt &) – Douglas Jul 20 '20 at 22:29
  • https://www.uvicorn.org/server-behavior/#graceful-process-shutdown – Andrew Nov 15 '22 at 21:23

5 Answers5

14

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.

Gustavo Kawamoto
  • 2,665
  • 18
  • 27
  • I'd like to use this tip of killing background uvicorn workers but when I try to run `kill $(pgrep -P $uvicorn_pid)` I get the following error : `pgrep: option requires an argument -- P` `kill: not enough arguments` – Vibhansh Jan 21 '22 at 09:51
  • 1
    You need to replace $uvicorn_pid with `uvicorn`'s PID, that's why `pgrep` is complaining about not having an argument. – Gustavo Kawamoto Jan 21 '22 at 11:04
  • Thank you for the quick reply. Still a beginner so got stuck. Cheers – Vibhansh Jan 21 '22 at 13:52
8
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

0

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
Denis Ryzhkov
  • 2,321
  • 19
  • 12
0

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}')" 
minion
  • 1
  • Having to use "kill -9" is not what I'm looking for, unfortunately. "kill -9" is a solution of last resort because something is not quite right. – Douglas Mar 13 '23 at 17:20
0

In case you're running uvicorn in Docker - simply stop the container like this:

docker ps # to get the CONTAINER ID
docker stop <CONTAINER ID>
tsveti_iko
  • 6,834
  • 3
  • 47
  • 39