race condition en generar numero de acta

Buenos dias,
queriamos reportar un posible race condition en la clase
/usr/local/proyectos/g3w3/src/siu/modelo/transacciones/admin_actas_examen_fc.php
en la funcion crear_encabezado
de guarani 3.12

Cuando dos sesiones diferentes de docentes generan un acta de examen desde 3w al mismo tiempo, el sistema les asigna el mismo numero de acta.

Hola Andres,

Pregunta, ¿esto les esta ocurriendo efectivamente o ven que es posible que llegara a ocurrir?

Estuve viendo el código (función crear_encabezado de la clase src/siu/modelo/transacciones/admin_actas_examen_fc.php), y no debería suceder esto, ya que los INSERTS que se hacen a la DB se hacen dentro del ámbito de una transacción (fíjate que se usan las funciones kernel::db()->abrir_transaccion(), kernel::db()->cerrar_transaccion() y si falla kernel::db()->abortar_transaccion()), esto lockea las tablas hasta que termine la transacción, con lo cual no se debería generar una Race Condition.

Quedo a la espera de tu respuesta.

saludos.

Hola, efectivamente esto nos esta ocurriendo en el ambiente de Produccion, y ocurre cuando dos actas de examen se intentan cerrar al mismo tiempo en 3w. Si se hacen en forma secuencial una atras de la otra, esto no ocurre.

Del codigo que se hace referencia en la funcion crear_encabezado, lo unico que se encuentra personalizado por nosotros es la funcion generar_nro_acta, en la cual tenemos que calcular el siguiente numero de una forma especial (ya que es el siguiente maximo de entre las actas del mismo origen y el mismo año relacionado), por lo que no modificamos nada relativo a la apertura o cierre de la transaccion, de manera que tampoco entendemos cual seria el problema.

Saludos!

Hola,

Es extraño, el numero de acta ya se asigna cuando se crea el acta, cuando se cierra solo se pasa a cerrada.

Te pediría que se me mandes los logs de cuando ocurre esto, los mismos están en la carpeta instalacion/log. Osea, hacelo con 2 actas en simultaneo y envíame los logs que se generan.

saludos.

Hola, perdon, lo escribi mal. No ocurre cuando se cierran al mismo tiempo, sino cuando se generan.

Saludos

Hola,

Estuve haciendo unas pruebas corriendo dos instancias de Postgres, y nos dimos cuenta que se puede dar lo que están comentando.

El problema es el SELECT MAX que se hace en el medio de la transacción, habría que agregar un bloqueo de tablas (LOCK) o algo por el estilo.

Por ahora estamos analizando la posible solución, ni bien sepamos les pasamos la solución. Si quieren ustedes también pueden aportar a la solución del problema.

saludos.

Hola, les consulto si tuvieron alguna novedad respecto a la solucion de este problema. Nosotros por nuestra parte no pudimos encontrarla.

Saludos

Hola, vamos a agregar un LOCK a la tabla sga_actas para que esto no ocurra.

Pueden agregarlo y probarlo en la función crear_encabezado del archivo src/siu/modelo/transacciones/admin_actas_examen_fc.php, agregar el LOCK debajo de la transacción:


                .........
                kernel::db()->abrir_transaccion();
		kernel::db()->ejecutar("LOCK TABLE sga_actas IN SHARE MODE;");
                .........

Ya hice unas pruebas usando dos sesiones del pgAdmin y parece funcionar.

saludos.

Buenos dias,
pudimos probar la sugerencia y funciono pero deben poner el lock adentro del try como se ve en el ejemplo:

kernel::db()->abrir_transaccion();

	try {
                    kernel::db()->ejecutar("LOCK TABLE sga_actas IN SHARE MODE;");

Ademas nos dimos cuenta de que esto tambien sucede en gestion, en la operacion “generar acta de examen”.
Esperamos que nos suban los parches para ambos casos (gestion y 3w).

Saludos cordiales

Hola Andres,

Vamos a analizarlo y ver de incorporarlo en la próxima versión, probablemente la 3.16 ya que necesitamos analizarlo y testearlo bien.

saludos.

Hola Andres, te confirmo que esto lo vamos a incorporar en la versión 3.16.0.

En cuanto a la solución, deberíamos utilizar el modo de bloqueo exclusivo, ya que sino se pueden hacer SELECTS y se seguiría generando mal el numero de acta.


kernel::db()->ejecutar("LOCK TABLE sga_actas IN ACCESS EXCLUSIVE MODE;");

saludos.