La tâche Django threadée ne gère pas automatiquement les transactions ou les connexions db?

J'ai configuré Django pour exécuter des tâches récurrentes dans leurs propres threads, et j'ai remarqué qu'ils laissaient toujours derrière eux des processus de connexion de base de données inachevés (pgsql "Idle In Transaction").

J'ai regardé dans les journaux Postgres et j'ai constaté que les transactions n'étaient pas terminées (pas de restauration). J'ai essayé d'utiliser les différents décorateurs de transactions sur mes fonctions, pas de chance.

Je suis passé à la gestion manuelle des transactions et j'ai fait la restauration manuellement, cela a fonctionné, mais encore laissé les processus comme "inactif".

Alors j'ai appelé connection.close(), et tout est bien.

Mais je me demande pourquoi la gestion typique des transactions et des connexions de Django ne fonctionne-t-elle pas pour ces tâches threadées qui sont générées à partir du thread principal de Django?

52
demandé sur Gabriel Hurley 2009-08-20 06:26:48

1 réponses

Après des semaines de test et de lecture du code source Django, j'ai trouvé la réponse à ma propre question:

Des Opérations

Le comportement autocommit par défaut de Django est toujours vrai pour ma fonction threadée. Cependant, il indique dans les documents Django:

Dès que vous effectuez une action qui doit écrire dans la base de données, Django produit les instructions INSERT/UPDATE/DELETE, puis effectue la validation. Il n'y a pas de restauration implicite.

Ce dernier la phrase est très littérale. Il n'émet pas de commande ROLLBACK à moins que quelque chose dans Django ait défini le drapeau dirty. Puisque ma fonction ne faisait que des instructions SELECT, elle n'a jamais défini le drapeau sale et n'a pas déclenché de validation.

Cela va à l'encontre du fait que PostgreSQL pense que la transaction nécessite une restauration car Django a émis une commande SET pour le fuseau horaire. En examinant les journaux, je me suis jeté parce que j'ai continué à voir ces instructions de restauration et supposé la transaction de Django la direction était la source. Il s'avère que ce n'est pas le cas, et C'est OK.

Connexions

La gestion des connexions est l'endroit où les choses deviennent difficiles. Il s'avère que Django utilise signals.request_finished.connect(close_connection) pour fermer la connexion à la base de données qu'il utilise normalement. Puisque rien ne se passe normalement dans Django qui n'implique pas de requête, vous prenez ce comportement pour acquis.

Dans mon cas, cependant, il n'y avait pas de demande car le travail était planifié. Pas de demande signifie pas de signal. Aucun signal signifie la base de données la connexion n'a jamais été fermé.

Pour en revenir aux transactions, il s'avère que le simple fait d'émettre un appel à connection.close() en l'absence de toute modification de la gestion des transactions émet l'instruction ROLLBACK dans le journal PostgreSQL que je cherchais.

Solution

La solution consiste à permettre à la gestion normale des transactions Django de se dérouler normalement et de fermer simplement la connexion de trois façons:

  1. Ecrire un décorateur qui ferme le connexion et envelopper les fonctions nécessaires.
  2. Branchez les signaux de requête existants pour que Django ferme la connexion.
  3. Fermer la connexion manuellement à la fin de la fonction.

L'un de ces trois va (et faire) travailler.

Cela m'a rendu fou pendant des semaines. J'espère que cela aide quelqu'un d'autre dans l'avenir!

95
répondu Gabriel Hurley 2009-08-28 11:22:05