2009-08-20 9 views
52

Tengo Django configurado para ejecutar algunas tareas recurrentes en sus propios subprocesos, y noté que siempre dejaban procesos de conexión de base de datos inacabados (pgsql "Idle In Transaction").¿La tarea de Django con subprocesos no maneja automáticamente las transacciones o conexiones db?

Miré a través de los registros de Postgres y encontré que las transacciones no se completaban (no 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 "inactivos".

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

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

Respuesta

93

Después de semanas de pruebas y la lectura del código fuente de Django, he encontrado la respuesta a mi propia pregunta:

Transacciones

comportamiento de confirmación automática por omisión de Django sigue siendo cierto para mi función de roscado. Sin embargo, se indica en la documentación de Django:

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

Esa última frase 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 complican. 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 instrucción ROLLBACK en el registro de PostgreSQL que había estado buscando.

soluciones

La solución es permitir la gestión normal de la transacción Django para proceder como normal y para cerrar simplemente la conexión de una de tres maneras:

  1. Escribir un decorador que cierra la conexión y envolver las funciones necesarias en él.
  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 los tres funcionará (y lo hará).

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

+1

Me alegro de que finalmente haya resuelto esto. No fue obvio Me pregunto si valdría la pena un boleto para agregar una nota en los documentos en algún lugar. –

+1

Este ticket describe un problema muy similar: http://code.djangoproject.com/ticket/9964 – zooglash

+0

Wow. ¿Hay alguna posibilidad de que puedas compartir el código? – Dejell

Cuestiones relacionadas