This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Healthcheck script for Puppeteer API
|
||||
Monitors the API endpoint and restarts the container if it fails
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import requests
|
||||
import docker
|
||||
from urllib.parse import quote
|
||||
from datetime import datetime
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.StreamHandler(),
|
||||
logging.FileHandler('/app/healthcheck.log')
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class PuppeteerHealthcheck:
|
||||
def __init__(self):
|
||||
self.base_url = os.getenv('BASE_URL', 'https://puppeteer.workwithkora.com')
|
||||
self.test_url = os.getenv('TEST_URL', 'https://www.google.com')
|
||||
self.api_key = os.getenv('API_KEY', 'Q7Sd#hhFkyHy*T')
|
||||
self.target_container = os.getenv('TARGET_CONTAINER', 'puppeteer-api')
|
||||
self.check_interval = int(os.getenv('CHECK_INTERVAL', '60'))
|
||||
|
||||
# Initialize Docker client
|
||||
try:
|
||||
self.docker_client = docker.from_env()
|
||||
logger.info("Docker client initialized successfully")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize Docker client: {e}")
|
||||
raise
|
||||
|
||||
logger.info(f"Healthcheck initialized with:")
|
||||
logger.info(f" Base URL: {self.base_url}")
|
||||
logger.info(f" Test URL: {self.test_url}")
|
||||
logger.info(f" Target Container: {self.target_container}")
|
||||
logger.info(f" Check Interval: {self.check_interval} seconds")
|
||||
|
||||
def perform_health_check(self):
|
||||
"""Perform the health check by making a request to the puppeteer API"""
|
||||
try:
|
||||
# Construct the URL with the test URL as a parameter
|
||||
encoded_test_url = quote(self.test_url, safe='')
|
||||
url = f"{self.base_url}/?url={encoded_test_url}"
|
||||
|
||||
headers = {
|
||||
'x-api-key': self.api_key,
|
||||
'User-Agent': 'Puppeteer-Healthcheck/1.0'
|
||||
}
|
||||
|
||||
logger.info(f"Performing health check: {url}")
|
||||
|
||||
response = requests.get(
|
||||
url,
|
||||
headers=headers,
|
||||
timeout=30,
|
||||
allow_redirects=True
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
logger.info("Health check passed - API is responding correctly")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"Health check failed - Status code: {response.status_code}")
|
||||
logger.warning(f"Response: {response.text[:200]}...")
|
||||
return False
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"Health check failed - Request error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Health check failed - Unexpected error: {e}")
|
||||
return False
|
||||
|
||||
def restart_container(self):
|
||||
"""Restart the target puppeteer-api container"""
|
||||
try:
|
||||
logger.info(f"Attempting to restart container: {self.target_container}")
|
||||
|
||||
# Get the container
|
||||
container = self.docker_client.containers.get(self.target_container)
|
||||
|
||||
# Restart the container
|
||||
container.restart(timeout=30)
|
||||
|
||||
logger.info(f"Successfully restarted container: {self.target_container}")
|
||||
return True
|
||||
|
||||
except docker.errors.NotFound:
|
||||
logger.error(f"Container not found: {self.target_container}")
|
||||
return False
|
||||
except docker.errors.APIError as e:
|
||||
logger.error(f"Docker API error while restarting container: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error while restarting container: {e}")
|
||||
return False
|
||||
|
||||
def run(self):
|
||||
"""Main loop for the healthcheck"""
|
||||
logger.info("Starting Puppeteer API healthcheck service")
|
||||
|
||||
consecutive_failures = 0
|
||||
max_consecutive_failures = 3 # Restart after 3 consecutive failures
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Perform health check
|
||||
if self.perform_health_check():
|
||||
consecutive_failures = 0
|
||||
logger.info("Health check passed - resetting failure counter")
|
||||
else:
|
||||
consecutive_failures += 1
|
||||
logger.warning(f"Health check failed - consecutive failures: {consecutive_failures}")
|
||||
|
||||
# Restart container if we've had too many consecutive failures
|
||||
if consecutive_failures >= max_consecutive_failures:
|
||||
logger.error(f"Health check failed {consecutive_failures} times consecutively - restarting container")
|
||||
if self.restart_container():
|
||||
consecutive_failures = 0
|
||||
logger.info("Container restarted successfully - resetting failure counter")
|
||||
else:
|
||||
logger.error("Failed to restart container")
|
||||
|
||||
# Wait before next check
|
||||
logger.info(f"Waiting {self.check_interval} seconds before next health check...")
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Healthcheck service stopped by user")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error in main loop: {e}")
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
try:
|
||||
healthcheck = PuppeteerHealthcheck()
|
||||
healthcheck.run()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to start healthcheck service: {e}")
|
||||
exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user