From 479ec4f917700e37aba44b539482248718726618 Mon Sep 17 00:00:00 2001 From: Marcin-Ramotowski Date: Wed, 11 Jun 2025 22:04:35 +0000 Subject: [PATCH] Added healthcheck --- api/app.py | 2 ++ api/tech_views.py | 20 ++++++++++++++++++++ api/utils.py | 3 +++ docker-compose.yml | 15 +++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 api/tech_views.py diff --git a/api/app.py b/api/app.py index 8ca7625..051bce1 100644 --- a/api/app.py +++ b/api/app.py @@ -4,6 +4,7 @@ from flask_jwt_extended import JWTManager from jwt import ExpiredSignatureError from models import db, RevokedToken import os +from tech_views import tech_bp from utils import init_db, wait_for_db from views import user_bp from werkzeug.exceptions import HTTPException @@ -26,6 +27,7 @@ def create_app(config_name="default"): # Blueprints registration app.register_blueprint(user_bp) + app.register_blueprint(tech_bp) # Database and JWT initialization db.init_app(app) diff --git a/api/tech_views.py b/api/tech_views.py new file mode 100644 index 0000000..0f2271c --- /dev/null +++ b/api/tech_views.py @@ -0,0 +1,20 @@ +from flask import Blueprint, jsonify +from models import db +from sqlalchemy import text +from utils import db_ready + +# Blueprint with technical endpoints +tech_bp = Blueprint('tech_bp', __name__) + +@tech_bp.route('/health', methods=['GET']) +def health_check(): + "Check if service works and database is functional" + try: + with db.engine.connect() as connection: + connection.execute(text("SELECT 1")) + return jsonify(status="healthy"), 200 + except Exception: + if db_ready: + return jsonify(status="unhealthy"), 500 + else: + return jsonify(status="starting"), 503 \ No newline at end of file diff --git a/api/utils.py b/api/utils.py index 2a1261e..3d51eb3 100644 --- a/api/utils.py +++ b/api/utils.py @@ -7,6 +7,7 @@ from sqlalchemy.exc import DatabaseError import time from werkzeug.security import generate_password_hash +db_ready = False def admin_required(user_id, message='Access denied.'): "Check if common user try to make administrative action." @@ -33,10 +34,12 @@ def get_user_or_404(user_id): def wait_for_db(max_retries): "Try to connect with database times." + global db_ready for _ in range(max_retries): try: with db.engine.connect() as connection: connection.execute(text("SELECT 1")) + db_ready = True return except DatabaseError: time.sleep(3) diff --git a/docker-compose.yml b/docker-compose.yml index 4717f40..dec3e28 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,24 @@ services: build: . env_file: - api/.env + ports: + - 80:80 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 15s db: container_name: db hostname: db image: mysql:latest env_file: - db/.env + ports: + - 3306:3306 + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + retries: 5