Where should I put my initialization code for a containerized flask application so that it gets executed after a host server reboot.
I currently have code to starts a Schedule thread in the main function ("if __name__ == '__main__':") to create a scheduled job to go and fetch a remote file.
This works mostly. However when the hosting server goes down or is rebooted, the container is set to automatically restart but does not not execute the initialization code when it comes back up.
I've also tried to create a separate function with the @app.before_first_request decorator but this doesn't seem to get executed either.
Both the main and before_first_request code runs if you explicitly restart the container (ie docker compose restart), but not if the host server is rebooted.
Edit to add Dockerfile & Code
Dockerfile (called by docker-compose which has restart: unless-stopped)
# For more information, please refer to https://aka.ms/vscode-docker-python
FROM python:3.10-alpine
EXPOSE 8000
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1
# Install pip requirements
COPY requirements.txt .
RUN python -m pip install -r requirements.txt
WORKDIR /workdir
COPY . /workdir
# Creates a non-root user with an explicit UID and adds permission to access the /app folder
# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /workdir
USER appuser
# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug
# CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app.app:app"]
CMD ["python3", "./app/app.py"]
/app/app.py (somewhat simplified)
app = Flask(__name__)
# used to create a separate thread for the scheduler
def init_scheduler():
# tries to run any pending jobs every 15 mins
while True:
app_logger.info(f"{schedule.idle_seconds()} seconds until next job")
schedule.run_pending()
# time.sleep(900)
time.sleep(30)
# fetch & save the image (real code omitted for brevity)
def fetch_image_job():
# main function
if __name__ == '__main__':
# fetches the current day's image in case it doesn't exist yet
fetch_image_job()
# schedule the ongoing job for SCHEDULED_TIME
schedule.every().day.at(SCHEDULED_TIME).do(fetch_image_job)
app_logger.info(f"Job scheduled to run every day at {SCHEDULED_TIME}")
# Start the scheduler in a separate thread
scheduler_thread = Thread(target=init_scheduler)
scheduler_thread.start()
app.run(host='0.0.0.0', port=8000)