HOWTO · Java

Java.Net.SocketTimeoutException: Tiempo de espera de lectura agotado en Tomcat

El tutorial de hoy discutirá las posibles razones y soluciones para java.net.SocketTimeoutException: lectura agotada en Tomcat en Java.

En esta página

Cuando Java muestra java.net.SocketTimeoutException: Read timed out, una lectura de socket no recibió datos antes de que venciera el tiempo de espera configurado para esa lectura. El mensaje por sí solo no permite saber si la demora se originó en un servicio remoto, la red, el trabajo de la aplicación o el tiempo de espera configurado por quien realizó la llamada. Primero localiza la lectura que falló y después ajusta únicamente el tiempo de espera que la controla.

Qué significa java.net.SocketTimeoutException: Read timed out

Un tiempo de espera de lectura limita cuánto espera una lectura de un socket Java para recibir datos. Es distinto del tiempo de espera de conexión, que controla otra fase de la comunicación. El seguimiento de pila puede indicar si la lectura pertenece a un cliente HTTP, un controlador de base de datos o el código de la aplicación; usa ese punto de llamada y los registros relacionados para identificar la operación.

El mensaje no demuestra que Tomcat no respondiera a un cliente. El proceso Java que lo registró podría estar leyendo de un servicio ascendente, y el otro extremo podría haber enviado algunos datos antes de que venciera el tiempo de espera de esa lectura. Cuando sea posible, relaciona el seguimiento de pila con los identificadores de solicitud, las marcas de tiempo y los registros de ambos extremos.

Identifica qué tiempo de espera está venciendo

Empieza por el seguimiento de pila de la excepción y localiza el primer marco de la aplicación o de una biblioteca que inició la lectura. Determina si está leyendo una respuesta HTTP, un resultado de base de datos u otro socket. Después consulta la configuración y la documentación de ese cliente para identificar su tiempo de espera de lectura o de respuesta. El tiempo de espera de un navegador o del frontend solo es pertinente si ese cliente controla la lectura que venció.

Si Tomcat aparece en el recorrido de la llamada, averigua qué proceso registró el error y qué conexión estaba leyendo. El tiempo de espera configurado en un cliente Java saliente es independiente de la configuración de un Connector de Tomcat. No deduzcas qué ajuste corresponde basándote únicamente en el texto de la excepción.

Configura el tiempo de espera de Tomcat pertinente

connectionTimeout es un ajuste del Connector de Tomcat, pero su comportamiento exacto y sus valores predeterminados dependen de la versión de Tomcat y del Connector utilizado. No equivale al tiempo de espera de lectura del socket de un cliente Java. Consulta la documentación de configuración de Connector de Tomcat 10.1 y, después, la documentación correspondiente a la versión de Tomcat desplegada. Comprueba que el ajuste cubra la operación identificada en el seguimiento de pila. La información disponible no indica qué versión de Tomcat se usa, por lo que no es seguro recomendar un cambio en el XML de Connector.

En un cliente Java que controla un socket, Socket.setSoTimeout configura las lecturas de ese socket. Este programa muestra el valor configurado con la etiqueta en inglés “Read timeout:”:

import java.io.IOException;
import java.net.Socket;

class ReadTimeoutSetup {
    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket()) {
            socket.setSoTimeout(5000);
            System.out.println("Read timeout: " + socket.getSoTimeout() + " ms");
        }
    }
}
Read timeout: 5000 ms

Este ejemplo no se conecta a un servidor ni modifica la configuración de Tomcat. Aplica un ajuste del lado del cliente solo en el componente que controla la lectura que venció y confirma que el valor elegido sea adecuado según la API de ese cliente y los requisitos operativos.

Diagnostica demoras de red, del servidor y de la aplicación

Comprueba las marcas de tiempo y los identificadores de solicitud en el cliente que realiza la llamada, Tomcat y los servicios ascendentes. Busca un intervalo sin datos de respuesta y compáralo con los errores de red, los registros del servidor y las trazas de la aplicación. Los datos pueden retrasarse por latencia de red, trabajo lento de la aplicación, una consulta de base de datos lenta, contención de recursos o carga concurrente; son posibles pistas que investigar, no conclusiones que puedan extraerse de la excepción por sí sola.

Revisa las métricas de CPU, memoria, hilos, grupos de conexiones y bases de datos para ese mismo intervalo. Comprueba si la solicitud pertinente llegó a la aplicación y si una llamada o consulta a un servicio posterior tardó más de lo habitual. Si el servicio está detrás de un proxy o balanceador de carga, compara sus tiempos de espera y registros con la cronología del cliente y del servidor. Cambia un ajuste pertinente a la vez y observa si se completa esa lectura, mientras sigues investigando el origen de la demora.

Gestiona de forma segura las solicitudes de larga duración

Si el trabajo realmente tarda más de lo que una solicitud síncrona puede esperar, considera procesarlo de forma asíncrona: devuelve una respuesta de aceptación con un identificador de trabajo, realiza el trabajo por separado y permite que el cliente consulte si ha terminado. Así se evita mantener abierta una solicitud durante todo el proceso, aunque requiere compatibilidad en la aplicación y una forma clara de informar sobre errores o avances.

Cuando corresponda esperar más, aumenta únicamente el tiempo de espera que controla la lectura identificada y procura que los límites relacionados del cliente, el proxy y el servidor sean compatibles. Las esperas excesivamente largas pueden ocupar hilos, sockets u otros recursos, además de ocultar que un servicio está perdiendo velocidad. Establece los valores a partir de la duración observada de las solicitudes y de la capacidad disponible; después, supervisa tanto las tasas de finalización como el uso de recursos.