Project

General

Profile

Development #81133

wcs et transactions PG

Added by Pierre Ducroquet 16 days ago. Updated 15 days ago.

Status:
En cours
Priority:
Normal
Target version:
-
Start date:
13 September 2023
Due date:
% Done:

0%

Estimated time:
Patch proposed:
No
Planning:
No

Description

On en a parlé tout à l'heure, j'ai creusé et voilà ce que j'ai trouvé...

https://www.psycopg.org/docs/connection.html#connection.autocommit
Ce paramètre est terriblement mal nommé.

Quand autocommit = False, par défaut, psycopg2 va automatiquement ouvrir une transaction à la première requête (donc en quelque sorte un autobegin), et si aucun .close(), .rollback() ou .commit() n'est réalisé, la session restera côté PG en idle in transaction.
Quand autocommit = True, psycopg2 ne fait plus rien, il se contente d'envoyer au PG les requêtes qu'on lui donne. Si on fait cursor.execute("begin"), alors on est dans une transaction.
Mais en dehors d'une transaction explicite, c'est PG qui ne fait que son fonctionnement par défaut où on peut, effectivement, considérer que chaque requête vit dans une transaction isolée automatique.

Le code de wcs/sql.py est couvert de commit() sur la plupart des chemins de code. Mais il en subsiste qui n'ont pas cet appel, comme SqlMixin::get, get_ids_from_query. À l'inverse, certaines fonctions enchaînent les .execute/.commit (par exemple SqlUser::get_reference_ids), ce qui est contre-productif puisque cela multiplie sans raison les fermetures de transaction alors que la ligne de code suivante va devoir en rouvrir une.

Pour ma part, je préfèrerais qu'on soit directement en autocommit = True, et qu'on protège par une transaction le code qui en a besoin. autocommit = False fait faire trop de magie à psycopg à mes yeux, et PG est bien assez grand pour clôturer la transaction dès que possible.
À défaut, il faut relire attentivement ce code pour s'assurer que tout soit bien fermé, et éventuellement chasser les ouvertures/fermetures successives inutiles.

Pour aussi voir les conséquences que ça a sur le pgbouncer, bien que non critiques : en autocommit = True, pgbouncer aura moins de messages à traiter certes, mais surtout les transactions seront plus courtes. Sur un strace cette nuit en recette, j'ai mesuré :

1694555871.298653 recvfrom(11, "Q\0\0\0\nBEGIN\0", 4096, 0, NULL, NULL)
1694555871.299041 sendto(11, "C\0\0\0\nBEGIN\0Z\0\0\0\5T", 17, 0, NULL, 0)
1694555871.299170 recvfrom(11, "Q\0\0\0\263SELECT id, title, s...
...
1694555871.302228 sendto(11, "9c9-8299-...
1694555871.302437 recvfrom(11, "Q\0\0\0\vCOMMIT\0", 4096, 0, NULL, NULL)
1694555871.302809 sendto(11, "C\0\0\0\vCOMMIT\0Z\0\0\0\5I", 18, 0, NULL, 0)

En autocommit = True, la transaction aurait duré environ 3ms, elle en a duré 4. L'écart est faible en absolu, mais c'est tout de même 30% de temps supplémentaire, et la majorité des requêtes sont au moins aussi rapides que celle-ci. Dès qu'un BEGIN arrive, pgbouncer associe une session PostgreSQL au client qui la demande, et ne la libère qu'au COMMIT ou ROLLBACK suivant.


Related issues

Related to w.c.s. - Development #81534: ajouter quelques conn.commit()Solution validée23 September 2023

Actions

History

#1

Updated by Benjamin Dauvergne 15 days ago

J'ai fait une analyse équivalente mais pas dans le contexte de l'utilisation d'un proxy mais pour l'utilisation des curseurs nommés ça aboutissait à la même conclusion (#57623-24).

#2

Updated by Robot Gitea 15 days ago

  • Status changed from Nouveau to En cours
  • Assignee set to Pierre Ducroquet

Pierre Ducroquet (pducroquet) a ouvert une pull request sur Gitea concernant cette demande :

#3

Updated by Frédéric Péters 5 days ago

Also available in: Atom PDF