python database django multithreading transactions

python - ¿La tarea de Django con subprocesos no maneja automáticamente las transacciones o conexiones db?



database multithreading (1)

Después de semanas de probar y leer el código fuente de Django, encontré la respuesta a mi propia pregunta:

Actas

El comportamiento de autocompromiso predeterminado de Django sigue siendo verdadero para mi función roscada. Sin embargo, dice en los documentos de Django:

Tan pronto como realice una acción que necesita escribir en la base de datos, Django produce las instrucciones INSERT / UPDATE / DELETE y luego realiza el COMMIT. No hay ROLLBACK implícito.

Esa última oración es muy literal. NO emite un comando ROLLBACK a menos que algo en Django haya establecido la bandera sucia. Como mi función solo hacía sentencias SELECT, nunca configuró la bandera sucia ni activó COMMIT.

Esto va en contra del hecho de que PostgreSQL cree que la transacción requiere un ROLLBACK porque Django emitió un comando SET para la zona horaria. Al revisar los registros, me deshice de ellos porque seguí viendo estas declaraciones ROLLBACK y asumí que la dirección de transacciones de Django era la fuente. Resulta que no es así, y eso está bien.

Conexiones

La gestión de la conexión es donde las cosas se ponen difíciles. Resulta que Django usa signals.request_finished.connect(close_connection) para cerrar la conexión de la base de datos que normalmente usa. Dado que normalmente no ocurre nada en Django que no implique una solicitud, se da por hecho este comportamiento.

En mi caso, sin embargo, no hubo una solicitud porque el trabajo estaba programado. Ninguna solicitud significa que no hay señal. Sin señal significa que la conexión de la base de datos nunca se cerró.

Volviendo a las transacciones, resulta que simplemente emitir una llamada a connection.close() en ausencia de cualquier cambio en la gestión de transacciones emite la declaración ROLLBACK en el registro de PostgreSQL que había estado buscando.

Solución

La solución es permitir que la administración normal de transacciones de Django continúe normalmente y que simplemente cierre la conexión de tres maneras:

  1. Escriba un decorador que cierre la conexión y ajuste las funciones necesarias en ella.
  2. Enganche las señales de solicitud existentes para que Django cierre la conexión.
  3. Cierre la conexión manualmente al final de la función.

Cualquiera de esos tres trabajará (y lo hará).

Esto me ha vuelto loco por semanas. ¡Espero que esto ayude a alguien más en el futuro!

Tengo Django configurado para ejecutar algunas tareas recurrentes en sus propios hilos, y noté que siempre dejaban procesos de conexión de base de datos inacabados (pgsql "Idle In Transaction").

Miré a través de los registros de Postgres y descubrí que las transacciones no se estaban completando (sin ROLLBACK). Intenté usar varios decoradores de transacciones en mis funciones, sin suerte.

Cambié a la gestión manual de transacciones y realicé la reversión manualmente, eso funcionó, pero aún dejó los procesos como "inactivo".

Entonces llamé a connection.close (), y todo está bien.

Pero me pregunto, ¿por qué la operación típica de Django y la gestión de conexiones no funcionan para estas tareas enhebradas que se generan a partir del hilo principal de Django?