Problème avec les cursors de Postgraphile

Je suis bloqué dans le dev de Tikka quand j’essaie d’utiliser les cursors de Postgraphile sur accounts.transferWithUd.

Et c’est reproductible car inhérent au fonctionnement des cursors.

Je fais une requête des 100 derniers virements de mon compte v1 sur la gtest :

query {
                accounts(
                    filter: {
                        id:{equalTo: "g1M5PtxdtmkVnaL6GFT94h6FW7MfF2rTfBitVkDtKX2kBTkQL"}
                    }
                ) {
                    nodes {
                        transferWithUd(
                            first: 100
            orderBy: TIMESTAMP_DESC
                      ) {
                        nodes {
                            id
                            amount
                            timestamp
                        }
                        pageInfo {
                            hasNextPage
                            hasPreviousPage
                            startCursor
                            endCursor
                        }
                        totalCount
                      }
                  }
              }
            }

Les cursors en réponse sont :

"pageInfo": {
              "hasNextPage": true,
              "hasPreviousPage": false,
              "startCursor": "WyJuYXR1cmFsIiwxXQ==",
              "endCursor": "WyJuYXR1cmFsIiwxMDBd"
            },

Les cursors sont des chaînes encodées en base64.

>>> b64decode("WyJuYXR1cmFsIiwxXQ==")
b'["natural",1]'
>>> b64decode("WyJuYXR1cmFsIiwxMDBd==")
b'["natural",100]'

En fait ce sont des offsets déguisés… Vous sentez la douille arriver ?

Maintenant je viens de faire un virement et je veux mettre à jour la liste en récupérant uniquement les virements précédents le startCursor WyJuYXR1cmFsIiwxXQ== :

query {
                accounts(
                    filter: {
                        id:{equalTo: "g1M5PtxdtmkVnaL6GFT94h6FW7MfF2rTfBitVkDtKX2kBTkQL"}
                    }
                ) {
                    nodes {
                        transferWithUd(
                            first: 100
                            before: "WyJuYXR1cmFsIiwxXQ"
                            orderBy: TIMESTAMP_DESC
                      ) {
                        nodes {
                            id
                            amount
                            timestamp
                        }
                        pageInfo {
                            hasNextPage
                            hasPreviousPage
                            startCursor
                            endCursor
                        }
                        totalCount
                      }
                  }
              }
            }
        

Résultat vide, ben oui, maintenant le dernier virement a la position de cursor 1, et donc y a rien avant pour Postgraphile :

{
  "data": {
    "accounts": {
      "nodes": [
        {
          "transferWithUd": {
            "nodes": [],
            "pageInfo": {
              "hasNextPage": false,
              "hasPreviousPage": false,
              "startCursor": null,
              "endCursor": null
            },
            "totalCount": 1102
          }
        }
      ]
    }
  }
}

L’IA me propose une solution que voici, ça vous paraît cohérent ?

Je cite :

La vérité sur les curseurs PostGraphile

Ce que tu décris est exact : quand le tri n’est pas basé sur un champ unique et immuable , les curseurs PostGraphile se comportent comme des offsets déguisés .

Pourquoi ?

PostGraphile génère des curseurs qui encodent :

  • La valeur du champ de tri (timestamp )
  • Un “natural” (position) ou un fallback

Mais si plusieurs enregistrements ont le même timestamp (ou si le tri n’est pas unique), le curseur n’est pas stable . Quand un nouvel enregistrement s’insère avec un timestamp différent, tous les curseurs existants deviennent invalides ou décalés .

C’est exactement ce que tu observes :

  • Curseur ["natural",1] → vide après insertion
  • Curseur ["natural",2] → fonctionne (décalé manuellement)

C’est un problème connu

PostGraphile utilise pg sous-jacent, et les curseurs sont basés sur :

sql

ORDER BY timestamp DESC, (tableoid, ctid)

Mais ctid change avec les insertions/suppressions, donc l’ordre n’est pas stable .

2. Ajouter une colonne de tri unique

Si tu peux modifier la base :

sql

ALTER TABLE transfers ADD COLUMN sort_id SERIAL; CREATE INDEX ON transfers (timestamp DESC, sort_id DESC);

Puis trier par [TIMESTAMP_DESC, SORT_ID_DESC]

3 Likes

Et bien, merci de relever ce bug :slight_smile:

Pour tout vous dire, depuis la migration g1, j’ai remarqué que dans gecko, lorsque le toggle DU est activé, l’historique des transaction de n’importe quel compte est capé à quelques tx max, impossible de remonter tout l’historique.

Mais comme personne n’a relevé ce bug jusqu’a présent, j’attendais de voir pour prendre la température. Ca montre que cette fonctionnalité n’est visiblement pas très utilisé. Tu es le premier à relever ce bug, félicitation tu as gagné le badge débusqueur compulsif !


Pas investigué côté squid, mais probablement un soucis avec la Vue SQL de cette query, à creuser.

Ca risque de devenir plus problématique à partir de la prochaine version de Gecko étant donné que j’ai activé ce toggle DU par defaut si il n’a jamais été touché par le user.

A première vue ton investiguation semble correct.

4 Likes