Projet

Général

Profil

Development #81133

wcs et transactions PG

Ajouté par Pierre Ducroquet il y a 8 mois. Mis à jour il y a 5 mois.

Statut:
Fermé
Priorité:
Normal
Assigné à:
Version cible:
-
Début:
13 septembre 2023
Echéance:
% réalisé:

0%

Temps estimé:
Patch proposed:
Non
Planning:
Non

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.


Demandes liées

Lié à w.c.s. - Development #81534: ajouter quelques conn.commit()Fermé23 septembre 2023

Actions

Révisions associées

Révision 33dee340 (diff)
Ajouté par Pierre Ducroquet il y a 5 mois

sql: switch the postgresql connection to autocommit (#81133)

As explained in #81133, the autocommit=False behaviour of psycopg2 is not
something we really want. It will automatically open transactions on the
server, closing them only when we commit, thus changing most of the
queries from a single roundtrip to three roundtrips. It also creates
longer transactions, thus reducing the opportunities for pgbouncer to
multiplex them. Last but not least, it makes forgetting a single
commit() call far more dangerous since it would possible leave an idle in
transaction session.
This changes to autocommit=True, ie. psycopg doesn't try anything and let
PostgreSQL do one transaction per statement, except when we explicitely
ask for one, with the new @atomic decorator.

Révision f48c49a5 (diff)
Ajouté par Pierre Ducroquet il y a 5 mois

sql: get rid of guard_postgres (#81133)

this was no longer needed

Révision 820ffd23 (diff)
Ajouté par Pierre Ducroquet il y a 5 mois

tests: add test for sql.atomic() (#81133)

Révision cabc133a (diff)
Ajouté par Pierre Ducroquet il y a 5 mois

sql: introduce Atomic.partial_commit() (#81133)

Historique

#1

Mis à jour par Benjamin Dauvergne il y a 8 mois

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

Mis à jour par Robot Gitea il y a 8 mois

  • Statut changé de Nouveau à En cours
  • Assigné à mis à Pierre Ducroquet

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

#3

Mis à jour par Frédéric Péters il y a 7 mois

#4

Mis à jour par Robot Gitea il y a 7 mois

  • Statut changé de En cours à Solution proposée
#5

Mis à jour par Robot Gitea il y a 7 mois

  • Statut changé de Solution proposée à En cours

Frédéric Péters (fpeters) a relu et demandé des modifications sur une pull request sur Gitea concernant cette demande :

#6

Mis à jour par Robot Gitea il y a 6 mois

Frédéric Péters (fpeters) a relu et demandé des modifications sur une pull request sur Gitea concernant cette demande :

#7

Mis à jour par Robot Gitea il y a 5 mois

  • Statut changé de En cours à Solution proposée
#8

Mis à jour par Robot Gitea il y a 5 mois

  • Statut changé de Solution proposée à Solution validée

Frédéric Péters (fpeters) a approuvé une pull request sur Gitea concernant cette demande :

#9

Mis à jour par Robot Gitea il y a 5 mois

  • Statut changé de Solution validée à Résolu (à déployer)

Frédéric Péters (fpeters) a mergé une pull request sur Gitea concernant cette demande :

#10

Mis à jour par Transition automatique il y a 5 mois

  • Statut changé de Résolu (à déployer) à Solution déployée
#11

Mis à jour par Transition automatique il y a 3 mois

Automatic expiration

Formats disponibles : Atom PDF