Timeouts
Los Timeouts son una herramienta esencial para mejorar el rendimiento, la seguridad y la estabilidad de los sistemas.
Timeout es un concepto que me encontré muchas veces al empezar a programar.
A menudo lo veía en documentos o archivos de configuración de aplicaciones o librerías.
No le daba importancia porque no sabía qué era ni para qué servía.
El Timeout es un elemento clave de cualquier aplicación, especialmente cuando se trata de conectividad.
Por eso, hoy te voy a contar:
¿Qué es?
¿Para qué sirve?
¿Por qué no esperar indefinidamente?
¿Qué situaciones requieren el uso de un timeout?
¿Cómo se pueden manejar los errores o interrupciones que se producen?
¿Qué problemas puedo tener si mi timeout es muy grande?
¿Qué problemas puedo tener si mi timeout es muy corto?
¿Qué tipos de timeout existen y cómo se diferencian?
¿Cuál es la mejor manera de definir el valor para timeout?
Conclusiones
¿Que es?
Un timeout es el límite de tiempo establecido para la ejecución de una operación.
Si la operación no se completa dentro de ese tiempo, se considera que ha ocurrido un timeout.
Por ejemplo, Pizza Hut te garantiza que te entregara tu pedido en 30 minutos.
Podríamos decir que el timeout para entregar la pizza es 30 minutos.
¿Para que sirve?
Cuando se excede el tiempo establecido del timeout, se pueden tomar medidas específicas.
Por ejemplo, en el caso de Pizza Hut, no te cobraran la pizza, te la dan gratis.
En el caso de una aplicación, podemos generar un error o intentar la operación nuevamente.
¿Por que no esperar indefinidamente?
Imagina que vas a depositar dinero en un cajero automático.
Accedes a tu cuenta, el cajero te pide que ingreses los billetes, los ingresas y luego el cajero se queda "procesando".
Si el sistema del banco tiene un fallo, ¿te gustaría que el cajero te dejara ahí esperando sin fin hasta que se solucione el problema?
Aquí es donde un timeout te puede ayudar.
Si la operacion de "procesar" el depósito no termina en 30 segundos (o el tiempo que tú elijas), el cajero podría darte un error, devolverte el dinero y pedirte que lo intentes de nuevo más tarde.
En el caso de una aplicación, esperar sin fin tendría estos problemas:
Los usuarios se frustrarian esperando que una operación se acabara. Esto les daría una mala impresión de tu aplicación y afectaría a los beneficios de tu empresa.
Tu aplicación se quedaría atascada hasta que la operación se acabara, y no podría atender a otros usuarios.
Si los servidores donde corre tu aplicación no están bien ajustados y tu aplicación tiene mucho tráfico, esto podría hacer que los usuarios mandaran muchas peticiones y colapsaran tu aplicación, y podría no recuperarse, incluso si la respuesta que esperaba tu aplicación volviera a funcionar pronto.
¿Que situaciones requieren el uso de un timeout?
Es muy importante que nuestra aplicación defina timeout para cada una de las dependencias externas que tenga:
Bases de Datos
Cache
Servicios Externos
También podemos usar un timeout en el servidor para devolver un error al cliente (aplicaciones móviles u otras) si una operación tarda más de lo que queremos.
De esa manera nuestros clientes pueden decidir que hacer.
Normalmente, las aplicaciones del lado del cliente y del servidor ya tienen timeouts por defecto.
Es importante que mirar la documentación y configuración de las librerías o servicios/dependencias para conocer esos valores por defecto.
¿Cómo se pueden manejar los errores o interrupciones que se producen?
Existen diferentes mecanismos o estrategias para manejar los errores generados por los timeouts, todo dependera de cual sea el escenario con el que nos enfrentemos:
Mecanismo de retry (reintento), este es el mecanismo mas comun, en el que se realiza una N cantidad de reintentos de la operacion antes de generar un error. Hay que ser cuidadosos con este mecanismo ya que si muchos clientes estan reintentando de manera constante, pueden agotar los recursos del servicio.
Hacer que nuestro sistema funcione en modo degradado (degraded mode). El funcionamiento degradado es cuando nuestro sistema sigue funcionando aunque no tenga todos los servicios/funcionalidades disponibles.
Por ejemplo, en el sitio de Amazon, cuando no funciona el servicio de calificación de productos, las calificaciones son escondidas y seguir comprando sin afectar la funcionalidad principal del sitio.
Mecanismo de circuit breaker (corto circuito), este mecanismo nos permite detectar cuando un servicio o un recurso está fallando o tardando demasiado en responder. En caso detectar algun problema, podemos cortar la comunicación con él hasta que se recupere. De esta manera, se evita que el sistema se colapse. Mientras nuestro sistema podria funcionar en modo degradado.
Puedes combinar o adaptar estas estrategias según tu sistema, el error y el impacto del timeout.
¿Que problemas puedo tener si el timeout es muy grande?
Dependiendo de la operación que estes realizando, si tu timeout es mas grande de lo necesario, puede generar los siguientes problemas:
Retener al usuario de manera innecesaria, generando una mala experiencia de usuario.
Si el sistema mantiene una conexion abierta que no esta utilizando, puede desperdiciar memoria, cpu y ancho de banda.
Un atacante puede bloquear todas las operaciones de nuestra aplicacion generando que nuestro servicio no este disponible para otros usuarios esto se conoce como ataque de denegación de servicio).
¿Que problemas puedo tener si el timeout es muy chico?
Tener un timeout chico puede generar que no esperes lo suficiente para completar una operacion causando los siguientes problemas:
Podemos perder datos necesarios para completar la operacion porque el sistema termina la conexion antes de completar la operacion.
Generar timeouts que sean falsos positivos ya que el sistema puede asumir que alguna dependencia esta fallando y disparar alarmas o algun mecanismo de retry o funcionamiento degradado de forma innecesaria. Esto afectaria la funcionalidad y rendimiento del sistema.
Generar conexiones nuevas innecesarias si el sistema vuelve a reintentar la conexión con demasiada frecuencia. Esto puede generar un tráfico excesivo o saturar el otro sistema, lo que puede provocar problemas de red o de seguridad.
¿Qué tipos de timeout existen y cómo se diferencian?
Connection Timeout: se usa para establecer un límite de tiempo para que se inicie una conexión entre dos dispositivos o aplicaciones. Si la conexión no se establece antes de que expire el timeout, se cancela el intento y se devuelve un error.
Read Timeout: se usa para establecer un límite de tiempo para que se reciba una respuesta o un dato de una fuente. Si la respuesta o el dato no se recibe antes de que expire el timeout, se interrumpe la lectura y se devuelve un error.
Write Timeout: se usa para establecer un límite de tiempo para que se envíe una solicitud o un dato a un destino. Si la solicitud o el dato no se envía antes de que expire el timeout, se interrumpe la escritura y se devuelve un error.
Session Timeout: se usa para establecer un límite de tiempo para que se mantenga una sesión activa entre dos dispositivos o aplicaciones. Si la sesión no se renueva o se cierra antes de que expire el timeout, se termina la sesión y se libera la conexión.
Execution Timeout: se usa para establecer un límite de tiempo para que se complete una tarea o un proceso. Si la tarea o el proceso no se completa antes de que expire el timeout, se detiene la ejecución y se devuelve un error.
Idle Timeout: se usa para establecer un límite de tiempo para que una conexión de la agrupación de conexiones pueda permanecer desocupada antes de que se pueda liberar la conexión. El idle timeout se usa para evitar que las conexiones inactivas consuman recursos innecesariamente y para liberar espacio para nuevas conexiones.
¿Cual es la mejor manera de definir el valor para un timeout?
No existe una formula que nos permita calcular cual es el valor indicado para definir un timeout.
Esto depende de varios factores:
Tipo de operacion
Tipo de sistema
Nivel de fiabilidad de la conexion
Impacto en la demora
Perdida de datos
Preferencias del usuario
En la mayoría de los casos, a mi parecer, el factor mas influyente, es el tipo de operación. Por ejemplo, descargar un archivo de varios GB tomará muchísimo mas tiempo que escribir un registro en una base de datos.
Por lo tanto el timeout para descargar un archivo será mucho mas grande que el de escritura a la base de datos.
Una forma para estimar el numero para el timeout seria hacer un test de carga y medir la latencia (p99) de esa operación.
Definiendo un timeout ligeramente superior al p99 podemos asumir que este timeout funcionaria sin problemas para el 99% de las operaciones.
Conclusiones
Todos los sistemas cuentan con timeouts, del lado del cliente y del lado del servidor.
Definir el valor correcto de un timeout, en combinación con estrategias para manejar errores, nos ayuda a tener sistemas resilientes, y por sobre todo, que la experiencia de usuario sea buena.
Utilizando tests de carga y latencia (p99) podemos encontrar un valor aproximado a lo ideal para nuestro timeout.
Espero que este articulo te haya gustado.