Cómo diagnosticar conexiones en estado idle in transaction
IMPORTANTE: ESTA ES UNA VERSIÓN BETA
Esta página está en desarrollo activo y puede contener funcionalidades inestables o incompletas. Úsela bajo su propia responsabilidad.
Visión general
Etendo atiende la mayoría de las solicitudes a través de DalFilter, que abre una sesión de Hibernate/DAL al inicio de la solicitud y la cierra una vez enviada la respuesta. Los servlets, procesos o endpoints de servicios web personalizados que llaman a OBDal.getInstance() o abren una sesión de SessionHandler fuera de ese ciclo de vida son responsables de cerrar la sesión ellos mismos.
Una sesión que nunca se cierra mantiene su conexión JDBC subyacente retirada del pool con una transacción abierta. PostgreSQL informa esa conexión como idle in transaction. Si no se controla, esto bloquea el autovacuum en las tablas que tocó la transacción, provoca hinchazón de las tablas y degrada el rendimiento de la base de datos con el tiempo. Reiniciar Tomcat vacía el pool y oculta el síntoma temporalmente, por lo que la fuga subyacente puede pasar inadvertida durante un tiempo.
Detección del problema
Consulte PostgreSQL para buscar conexiones atascadas en este estado:
SELECT pid, now() - xact_start AS duration, state, LEFT(query, 80) AS query_snippet
FROM pg_stat_activity
WHERE state = 'idle in transaction';
Un número creciente de filas que nunca se despeja hasta que se reinicia Tomcat indica que, en algún punto del recorrido de la solicitud, no se está cerrando una sesión.
Cómo encontrar la fuga
Revise los caminos de código personalizados que abren una sesión DAL o de Hibernate directamente en lugar de depender de DalFilter. Esto es habitual en servlets que extienden directamente HttpServlet o HttpBaseServlet, evitando la cadena de filtros estándar. Cada uno de estos caminos debe cerrar su sesión explícitamente en un bloque finally:
try {
// ... procesamiento de la solicitud que usa OBDal.getInstance() ...
} finally {
OBDal.getInstance().commitAndClose();
}
O, cuando se usa SessionHandler directamente:
try {
// ... procesamiento de la solicitud ...
} finally {
SessionHandler.getInstance().commitAndClose();
}
Para confirmar qué camino de código es responsable antes de cambiar nada, habilite el registro de conexiones abandonadas. Esto registra la traza de pila de dónde se tomó prestada una conexión una vez que ha estado retirada más tiempo del esperado, sin cerrar nada:
Aplique el cambio con:
Warning
Registrar las conexiones abandonadas añade sobrecarga a cada solicitud de conexión, porque se debe generar una traza de pila. Utilícelo para diagnosticar la fuga y luego deshabilítelo una vez identificado el camino de código responsable.
Mitigación a nivel de pool
Mientras se desarrolla e implementa la corrección de código, el pool de conexiones puede configurarse para recuperar por la fuerza las conexiones que se han retirado durante demasiado tiempo. Añada las siguientes propiedades a gradle.properties:
Luego aplique el cambio:
Consulte Cómo usar un pool de conexiones externo para ver la referencia completa de las propiedades de configuración del pool.
Warning
Establezca removeAbandonedTimeout con un margen amplio por encima de la duración de la transacción o el proceso en segundo plano legítimo más largo del entorno. Cualquier operación que siga en ejecución más allá de ese tiempo de espera tendrá su conexión recuperada mientras está en uso, lo que corrompe esa operación. Este ajuste es una red de seguridad temporal, no un sustituto de cerrar la sesión en el código.
This work is licensed under CC BY-SA 2.5 ES by Futit Services S.L.