Is there a way to kill uvicorn cleanly?

Viewed 14574

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

2 Answers

That's because you're running uvicorn as your only server. The uvicorn is not a process manager and, as so, it does not manage it's 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 it's 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
Related