Gesundheitswächter is a lightweight, Dockerized component that continuously monitors a prioritized list of URLs. It identifies and returns the highest-priority healthy URL, designed to facilitate active-passive failover in multi-region setups.
- URL Input & Prioritization: Accepts a comma-separated list of URLs via the
HEALTH_CHECK_URLSenvironment variable. Priority is determined by the order in the list. - Health Check Mechanism: Periodically checks each URL for an HTTP 2xx status code. Interval and timeout are configurable.
- HTTP API Endpoint: Exposes
/healthy-endpoint(or/status) to return the current highest-priority healthy URL in JSON format. - Logging: Provides basic logging for startup, health checks, and status changes.
- Dockerized: Easily buildable and runnable as a Docker container.
The component is configured using environment variables:
HEALTH_CHECK_URLS(required): A comma-separated string of URLs to monitor.- Example:
"http://region1.example.com/health,http://region2.example.com/api/status,http://region3.backup.com/ping" - The first URL has the highest priority (P1), the second is P2, and so on.
- Example:
HEALTH_CHECK_INTERVAL_SECONDS(optional): The interval in seconds between health checks for each URL.- Default:
5
- Default:
HEALTH_CHECK_TIMEOUT_SECONDS(optional): The timeout in seconds for each HTTP health check request.- Default:
2
- Default:
FLASK_APP(internal): Specifies the entry point for the Flask application.- Default:
app.py(should not need to be changed for normal operation)
- Default:
FLASK_RUN_HOST(internal): Specifies the host the Flask app will listen on.- Default:
0.0.0.0(to be accessible from outside the container)
- Default:
FLASK_RUN_PORT(optional): Specifies the port the Flask app will listen on.- Default:
5000(as defined by Flask's default and exposed in Dockerfile)
- Default:
- Docker installed and running on your system.
Navigate to the directory containing the Dockerfile, app.py, and requirements.txt. Run the following command:
docker build -t gesundheitswaechter .This will build the Docker image and tag it as gesundheitswaechter.
To run the container, you need to provide the HEALTH_CHECK_URLS environment variable. You can also override other optional environment variables.
Example:
docker run -d -p 5000:5000 \
-e HEALTH_CHECK_URLS="http://mock-server-1:8080/health,http://mock-server-2:8081/status,http://nonexistent.example.com/ping" \
-e HEALTH_CHECK_INTERVAL_SECONDS=10 \
--name health-guardian \
gesundheitswaechterExplanation of flags:
-d: Run the container in detached mode (in the background).-p 5000:5000: Map port 5000 on the host to port 5000 in the container (where the Flask app runs).-e HEALTH_CHECK_URLS=...: Sets the URLs to monitor. Replace with your actual URLs.-e HEALTH_CHECK_INTERVAL_SECONDS=10: (Optional) Sets the health check interval to 10 seconds.--name health-guardian: (Optional) Assigns a name to the running container for easier management.gesundheitswaechter: The name of the Docker image to use.
Note on URLs: If you are testing locally with other Docker containers (e.g., mock servers), ensure they are on the same Docker network or use appropriate hostnames/IPs accessible from the gesundheitswaechter container.
Once the container is running, you can query its status endpoint:
curl http://localhost:5000/healthy-endpointOr, using a browser, navigate to http://localhost:5000/healthy-endpoint (or http://localhost:5000/status).
Example Responses:
-
If a healthy URL is found:
{ "healthy_url": "http://mock-server-1:8080/health" } -
If no URLs are healthy:
{ "status": "all_endpoints_down", "message": "No healthy endpoints available." }(This will be returned with an HTTP 503 status code.)
To view the logs from the running container:
docker logs health-guardian(Replace health-guardian with your container name or ID if you didn't specify one or used a different name.)
- Clone the repository (if applicable) or ensure you have
app.py,requirements.txt, andDockerfile. - Install dependencies locally (optional, for direct execution without Docker):
pip install -r requirements.txt
- Run the Flask app directly (ensure environment variables are set in your shell):
export HEALTH_CHECK_URLS="http://localhost:8000/health,http://localhost:8001/status" # export other variables as needed python app.py
This will start the Flask development server.
To thoroughly test Gesundheitswächter, you can set up simple mock HTTP servers that simulate your actual services.
You can create one or more simple Python Flask applications to act as mock servers. Save each in a separate file (e.g., mock_server_1.py, mock_server_2.py).
Example mock_server_1.py (Healthy):
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/health')
def health_check():
return jsonify(status="ok"), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080) # Expose on port 8080Example mock_server_2.py (Initially Healthy, can be made unhealthy):
from flask import Flask, jsonify
import os
app = Flask(__name__)
# Simulate health status, can be changed by an env var or by modifying the file
# For simplicity, we'll make it always healthy here, but you can add logic
# to make it fail based on some condition for testing failover.
@app.route('/status')
def health_check():
# To simulate failure, you could change this to return 500
return jsonify(status="ready"), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8081) # Expose on port 8081For easier networking with the gesundheitswaechter container, run your mock servers in Docker as well.
Dockerfile for mock servers (e.g., Dockerfile.mock):
FROM python:3.9-slim
WORKDIR /app
COPY . /app
RUN pip install Flask
# Adjust CMD based on which mock server you are building
# CMD ["python", "mock_server_1.py"]
# CMD ["python", "mock_server_2.py"]Build and run each mock server:
# For mock_server_1.py (assuming it's in a directory 'mock1')
# Create Dockerfile.mock in 'mock1' with CMD ["python", "mock_server_1.py"]
# cd mock1
# docker build -t mock-server-1 -f Dockerfile.mock .
# docker run -d --name mock1-container -p 8080:8080 mock-server-1
# cd ..
# For mock_server_2.py (assuming it's in a directory 'mock2')
# Create Dockerfile.mock in 'mock2' with CMD ["python", "mock_server_2.py"]
# cd mock2
# docker build -t mock-server-2 -f Dockerfile.mock .
# docker run -d --name mock2-container -p 8081:8081 mock-server-2
# cd ..Networking Note: If running mock servers as Docker containers, you can use their container names as hostnames in HEALTH_CHECK_URLS if they are on the same Docker network. Create a custom Docker network:
docker network create healthcheck-netThen run your mock servers and gesundheitswaechter on this network:
# Example for mock server 1
docker run -d --name mock1-container --network healthcheck-net -p 8080:8080 mock-server-1
# Example for mock server 2
docker run -d --name mock2-container --network healthcheck-net -p 8081:8081 mock-server-2
# And for Gesundheitswächter
docker run -d -p 5000:5000 \
--network healthcheck-net \
-e HEALTH_CHECK_URLS="http://mock1-container:8080/health,http://mock2-container:8081/status,http://nonexistent.example.com/ping" \
--name health-guardian \
gesundheitswaechterIf not using a custom network and mock servers are run via docker run -p <host_port>:<container_port>, you might need to use host.docker.internal (on Docker Desktop) or your machine's IP address for the URLs if gesundheitswaechter needs to reach them via the host. For simplicity, using a shared Docker network is recommended.
Build the gesundheitswaechter image if you haven't already:
docker build -t gesundheitswaechter .Run the gesundheitswaechter container, pointing HEALTH_CHECK_URLS to your mock servers.
If using the Docker network healthcheck-net and container names mock1-container, mock2-container:
docker run -d -p 5000:5000 \
--network healthcheck-net \
-e HEALTH_CHECK_URLS="http://mock1-container:8080/health,http://mock2-container:8081/status,http://unreachable-mock.com/status" \
-e HEALTH_CHECK_INTERVAL_SECONDS=5 \
--name health-guardian \
gesundheitswaechterIf your mock servers are running directly on your host machine (e.g., python mock_server_1.py) and accessible via localhost:
You might need to use host.docker.internal (on Docker Desktop for Windows/Mac) or your host's IP address in HEALTH_CHECK_URLS.
Example for Docker Desktop:
docker run -d -p 5000:5000 \
-e HEALTH_CHECK_URLS="http://host.docker.internal:8080/health,http://host.docker.internal:8081/status" \
--name health-guardian \
gesundheitswaechter-
Check Logs:
docker logs -f health-guardian docker logs -f mock1-container # If running mock server in DockerYou should see logs from
gesundheitswaechterindicating startup configuration and health check attempts. -
Query Endpoint:
curl http://localhost:5000/healthy-endpoint
Initially, it should return the highest priority healthy mock server (e.g.,
http://mock1-container:8080/health).
-
Stop a Mock Server:
docker stop mock1-container # Stop the P1 server -
Observe Logs and Endpoint:
gesundheitswaechterlogs should show P1 failing.- After a short delay (based on
HEALTH_CHECK_INTERVAL_SECONDS), queryinghttp://localhost:5000/healthy-endpointshould now return the P2 server (e.g.,http://mock2-container:8081/status).
-
Stop All Mock Servers:
docker stop mock2-container # Stop the P2 server as well -
Observe Logs and Endpoint:
gesundheitswaechterlogs should show P2 failing.- Querying
http://localhost:5000/healthy-endpointshould now return:{ "status": "all_endpoints_down", "message": "No healthy endpoints available." }
-
Restart a Mock Server:
docker start mock1-container # Bring P1 back online -
Observe Logs and Endpoint:
gesundheitswaechterlogs should show P1 becoming healthy again.- Querying
http://localhost:5000/healthy-endpointshould revert to P1.
This testing process allows you to verify the core logic of prioritization and failover.
This completes the initial setup for Gesundheitswächter.