2009-08-20 14 views
52

Ho impostato Django per eseguire alcune attività ricorrenti nei propri thread e ho notato che si lasciavano sempre dietro processi di connessione al database non completati (pgsql "Idle In Transaction").L'attività Django filettata non gestisce automaticamente le transazioni o le connessioni db?

Ho controllato i registri di Postgres e ho rilevato che le transazioni non venivano completate (nessun ROLLBACK). Ho provato a utilizzare i vari decoratori di transazioni sulle mie funzioni, senza fortuna.

Sono passato alla gestione delle transazioni manuali e ho eseguito manualmente il rollback, che ha funzionato, ma ho lasciato i processi come "Idle".

Quindi ho chiamato connection.close() e tutto va bene.

Ma mi chiedo, perché la tipica gestione delle transazioni e delle connessioni di Django non funziona per questi processi threaded che vengono generati dal thread principale di Django?

risposta

93

Dopo settimane di test e lettura del codice sorgente di Django, ho trovato la risposta alla mia domanda:

transazioni

comportamento autocommit predefinito di Django è ancora valido per la mia funzione filettato. Tuttavia, si afferma nei documenti Django:

Non appena si esegue un'azione che deve scrivere nel database, Django produce le istruzioni INSERT/UPDATE/DELETE e quindi COMMIT. Non c'è ROLLBACK implicito.

Quest'ultima frase è molto letterale. NON emette un comando ROLLBACK a meno che qualcosa in Django non abbia impostato la flag dirty. Poiché la mia funzione stava facendo solo istruzioni SELECT, non ha mai impostato la flag dirty e non ha attivato un COMMIT.

Questo va contro il fatto che PostgreSQL pensa che la transazione richieda un ROLLBACK perché Django ha emesso un comando SET per il fuso orario. Nel rivedere i log, mi sono buttato fuori perché continuavo a vedere queste dichiarazioni ROLLBACK e ho assunto che la gestione delle transazioni di Django fosse la fonte. Si scopre che non lo è, e va bene.

Connessioni

La gestione connessione è dove le cose si fanno difficili. Django utilizza signals.request_finished.connect(close_connection) per chiudere la connessione al database che normalmente utilizza. Dal momento che in Django non accade normalmente nulla che non implichi una richiesta, si dà per scontato questo comportamento.

Nel mio caso, tuttavia, non è stata richiesta perché il processo era pianificato. Nessuna richiesta significa nessun segnale. Nessun segnale significa che la connessione al database non è mai stata chiusa.

Tornando alle transazioni, si scopre che è sufficiente emettere una chiamata a connection.close() in assenza di eventuali modifiche ai problemi di gestione delle transazioni dell'istruzione ROLLBACK nel registro PostgreSQL che stavo cercando.

Soluzione

La soluzione è quella di consentire il normale gestione delle transazioni Django procedere come normale e per chiudere semplicemente il collegamento uno dei tre modi:

  1. Scrivi un decoratore che chiude la connessione e avvolgere le funzioni necessarie in esso.
  2. Agganciare ai segnali di richiesta esistenti per fare in modo che Django chiuda la connessione.
  3. Chiudere la connessione manualmente alla fine della funzione.

Ognuno di questi tre lavori (e lo farà).

Questo mi ha fatto impazzire per settimane. Spero che questo aiuti qualcun altro in futuro!

+1

Felice di averlo finalmente risolto. Non era ovvio. Mi chiedo se potrebbe valere un biglietto per aggiungere una nota nei documenti da qualche parte. –

+1

Questo ticket descrive un problema molto simile: http://code.djangoproject.com/ticket/9964 – zooglash

+0

Wow. qualche possibilità che tu possa condividere il codice? – Dejell

Problemi correlati