En las aplicaciones modernas, la conectividad continua es clave, especialmente para las aplicaciones móviles que dependen de servicios backend. En este blog, veremos una solución basada en Python que supervisa el estado de los servidores de servicios de aplicaciones y, si es necesario, conmuta automáticamente a un servidor secundario. Este código de ejemplo utiliza comprobaciones de estado HTTP y puntos finales de conexión WebSocket para garantizar que la aplicación siempre se conecte a un servicio en buen estado.
Visión general
La solución implica dos tipos de puntos finales:
-
- URL de chequeo
- Estos puntos finales (por ejemplo
https://.../_ping) se sondean mediante HTTP CABEZA peticiones. - Determinan si el servidor de servicios de aplicaciones está en buen estado.
- Estos puntos finales (por ejemplo
- Puntos finales de conexión
- Se trata de las direcciones URL de WebSocket (p. ej,
wss://.../primary) que tu aplicación utiliza para interactuar con el backend. - El punto final de conexión activo se actualiza en función de los resultados de la comprobación de estado.
- Se trata de las direcciones URL de WebSocket (p. ej,
- URL de chequeo
Si la comprobación de estado del servidor primario falla consecutivamente, la lógica de conmutación por error cambiará la conexión de la aplicación al servidor secundario.
El código en detalle
A continuación se muestra el código completo con comentarios en línea y explicaciones detalladas:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
import logging import threading import requests from time import sleep # Configure logging to show time-stamped messages at INFO level. logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s') # -------------------------------------- # Health Check URLs (App Service Servers) # -------------------------------------- # These URLs are used for health checking the servers by sending HEAD requests. health_check_urls = { "primary": "https://XXXXXXXXXXXXXX.apps.cloud.couchbase.com:4984/_ping", "secondary": "https://XXXXXXXXXXXXXX.apps.cloud.couchbase.com:4984/_ping" } # ------------------------------------- # Connection Endpoints (WebSocket URLs) # ------------------------------------- # These endpoints are what your application actually uses for connections. connection_urls = { "primary": "wss://XXXXXXXXXXXXXX.apps.cloud.couchbase.com:4984/primary", "secondary": "wss://XXXXXXXXXXXXXX.apps.cloud.ucouchbase.com:4984/secondary" } # The variable `active_cluster` tracks which server is currently active. active_cluster = "primary" # This variable holds the actual WebSocket URL used by your application. active_connection_url = connection_urls[active_cluster] def is_cluster_healthy(url): """ Perform a health check using a HEAD request against the provided URL. Returns True if the response status is 200; otherwise, returns False. Logs the status code and headers for troubleshooting. """ try: response = requests.head(url, timeout=5) logging.info(f"Health Check Response for {url}") logging.info(f" Status Code: {response.status_code}") logging.info(" Headers:") for header, value in response.headers.items(): logging.info(f" {header}: {value}") if response.status_code == 200: logging.info(f"{url} is healthy!") return True else: logging.warning(f"{url} might be unhealthy or unreachable.") return False except requests.exceptions.RequestException as e: logging.error(f"Health check failed for {url}: {e}") return False def health_check_worker(): """ A background worker that checks the health of the active server every 3 seconds. If the active server fails health checks for more than 9 consecutive times, the worker attempts to switch to the other server. """ global active_cluster global active_connection_url consecutive_failures = 0 while True: sleep(3) # Wait 3 seconds between checks. # Use the HTTP health check endpoint for the active cluster. current_health_url = health_check_urls[active_cluster] logging.info(f"Health check: Checking {active_cluster} at {current_health_url}...") if is_cluster_healthy(current_health_url): consecutive_failures = 0 # Reset counter if healthy. else: consecutive_failures += 1 logging.warning(f"{active_cluster} health check failed {consecutive_failures} time(s).") # If failures exceed 9 consecutive attempts, try to fail over. if consecutive_failures > 9: logging.error(f"{active_cluster} is considered down. Attempting to fail over...") # Determine the new active cluster. new_cluster = "secondary" if active_cluster == "primary" else "primary" new_health_url = health_check_urls[new_cluster] # Check if the new cluster is healthy. if is_cluster_healthy(new_health_url): active_cluster = new_cluster # Update the connection endpoint. active_connection_url = connection_urls[new_cluster] logging.warning(f"Switched active cluster to {new_cluster}.") logging.warning(f"New WebSocket connection endpoint: {active_connection_url}") else: logging.critical("Both clusters appear to be down!") consecutive_failures = 0 # Reset the failure counter after the attempt. def main(): """ Main function to start the health-check worker in a background thread. Keeps the script running indefinitely until interrupted. """ thread = threading.Thread(target=health_check_worker, daemon=True) thread.start() logging.info("Health check worker started. Press Ctrl+C to exit.") logging.info(f"Application will initially connect to: {active_connection_url}") try: while True: sleep(1) # Main thread remains alive. except KeyboardInterrupt: logging.info("Shutting down health check script.") if __name__ == "__main__": main() |
Puntos técnicos clave
-
- Comprobaciones de estado de los servidores App Service:
El código separa el puntos finales del chequeo (utilizado para la supervisión) del puntos finales de conexión (utilizado por su aplicación). Esto le permite comprobar el estado del servidor de forma independiente mientras mantiene un punto final de conexión estable. - Solicitudes HTTP HEAD:
Utilizando CABEZA solicitudes a la/_pingminimiza la transferencia de datos al tiempo que proporciona códigos de estado y cabeceras para el diagnóstico. - Hilo de fondo:
Enchequeo_trabajadorse ejecuta en su propio subproceso, lo que permite una supervisión continua sin bloquear el subproceso principal de la aplicación. - Lógica de conmutación por error:
- Un contador (
fracasos_consecutivos) realiza un seguimiento de los fallos consecutivos. - Si el recuento supera un umbral establecido (9 fallos), el script intenta una conmutación por error comprobando el estado del servidor alternativo.
- Tras una comprobación de estado satisfactoria en el servidor secundario, se actualiza el punto final de conexión activo.
- Un contador (
- Registro:
El registro detallado proporciona información sobre el proceso de comprobación de estado, incluidos el estado de respuesta HTTP, las cabeceras y los eventos de conmutación por error. Esto facilita la resolución de problemas y la supervisión.
- Comprobaciones de estado de los servidores App Service:
Adaptación a su aplicación
-
- Puedes traducir y adaptar fácilmente este código a tu lenguaje de programación preferido, como Swift y Kotlin, para adaptarlo a las necesidades de tu aplicación.
- Puede integrar esta secuencia de comandos o lógica en su código móvil (iOS/Android) o un servicio backend que actualiza el activo punto final.
- Si utiliza iOS o Android, tenga en cuenta con qué frecuencia y dónde ejecuta este código. Por ejemplo, las tareas en segundo plano o las notificaciones push pueden activar comprobaciones de estado en un contexto móvil.
- Si usted tiene una arquitectura de microservicios, puede ejecutar esta lógica de conmutación por error en un pequeño servicio que expone un archivo URL activa actual a las aplicaciones móviles, para que siempre se conecten al punto final de WSS correcto.
Conclusión
Este código de ejemplo proporciona un mecanismo sencillo pero potente para garantizar la alta disponibilidad de las aplicaciones mediante la conmutación automática a un servidor de copia de seguridad cuando el servidor primario deja de estar accesible. Al separar las comprobaciones de estado de los puntos finales de conexión, la aplicación garantiza que siempre se conecta a un servidor en buen estado a través de WebSocket.
En un entorno de producción, es posible que tenga que adaptar y ampliar la lógica para adaptarla a sus requisitos específicos, las condiciones de la red y las políticas de seguridad.
Implementar esta lógica en su aplicación móvil o servicio backend puede mejorar enormemente el tiempo de actividad y la resistencia, garantizando que sus usuarios sigan conectados incluso durante interrupciones inesperadas del servicio.