How to most correctly restart FastAPI inside a Docker container

Viewed 77

When restarting the physical server, my web server starts before the database.
If the web service can't connect to the database I would like to restart the container (I use docker-compose with restart: always).

Run command in Dockerfile:
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]

Database initialization (I use sqlalchemy) at web service startup:

try:
    engine = create_engine(...)
    metadata.create_all(engine)
except Exception as e:
    print(e)
    exit(1)

But exit(1) only kills Python while Uvicorn keeps running.

# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  3.0  0.3 100608 24992 ?        Ssl  14:13   0:01 /usr/local/bin/python /usr/local/bin/uvicorn main:app --reload --host 0.0.0.0 --port 8000
root         7  0.1  0.1  13112 10828 ?        S    14:13   0:00 /usr/local/bin/python -c from multiprocessing.resource_tracker import main;main(4)
root         8  2.3  0.0      0     0 ?        Z    14:13   0:01 [python] <defunct>

I could create and specify in the Dockerfile a python file that checks the connection to the base, and if everything is fine, it starts Uvicorn, which already starts my current main. But maybe there is some more elegant way?

1 Answers

I know it's not exactly an answer to your question, but I'd either

  • use wait-for-it.sh to have your web container wait for the database to be up, or
  • without extra dependencies, have that init phase retry a couple of times before giving up:
for attempt in range(10):
    try:
        engine = create_engine(...)
        metadata.create_all(engine)
    except ConnectionError as e:  
        # TODO: replace "ConnectionError" with the particular connection error
        time.sleep(5)
    else:
        break
else:  # if we didn't `break` out, we've run out of attempts
    raise RuntimeError("Database connection error :(")
Related