MongoDB : Résoudre l'erreur "TransientError - Transaction aborted"
Article publié le 20/07/2021, dernière mise à jour le 22/10/2024
La famille d'erreurs "TransientError" en MongoDB indique qu'une erreur est survenue mais que rien ne garanti que cette erreur apparaitra de nouveau si l'on relance le même code.
Mais qu'est-ce que cela signifie ?
Cela veut dire que la cause de l'erreur ne provient pas de la requête (ou de l'ensemble des requêtes dans le cas d'une transaction), mais peut provenir d'un facteur extérieur.
L'exemple le plus simple est une micro-coupure du réseau au moment d'une requête : cette dernière n'a pas pu s'exécuter correctement, mais si on la relance tout peut très bien se passer.
En résumé, TransientError = vous pouvez retenter la requête.
On trouve comme cause le réseau, éventuellement le manque d'espace disque et d'autres causes plus pernicieuses avec des noms et des codes qui ne donnent pas beaucoup d'indices sur l'origine de l'erreur, comme par exemple "NoSuchTransaction".
NoSuchTransaction - Transaction X has been aborted
Si cette erreur vous est familière et que vous êtes ici, c'est sûrement parce que vous n'avez pas pu trouver l'origine, et pour cause cette erreur ne nous apprends pas grands chose, et la documentation non plus.
Prenons le code entier de cette erreur :
{ MongoError: Transaction 1 has been aborted.
at server/node_modules/mongodb-core/lib/connection/pool.js:581:63
at authenticateStragglers (/server/node_modules/mongodb-core/lib/connection/pool.js:504:16)
at Connection.messageHandler (server/node_modules/mongodb-core/lib/connection/pool.js:540:5)
...
errorLabels: [ 'TransientTransactionError' ],
operationTime:
Timestamp { _bsontype: 'Timestamp', low_: 2, high_: 1544250067 },
ok: 0,
errmsg: 'Transaction 1 has been aborted.',
code: 251,
codeName: 'NoSuchTransaction',
...
}
En essayant de le déchiffrer, on comprend que la transaction n'existe plus : "NoSuchTransaction".
Pourquoi ? Car elle a été annulée par le système lui-même : "Transaction 1 has been aborted."
Mais pourquoi cette transaction a-t-elle été annulée ?
Il y a fort à parier que vous ayez reçu cette erreur après avoir attendu la fin de la transaction pendant un certain moment. Tout simplement parce que cette erreur indique que la transaction a été annulée car elle mettait trop de temps à s'exécuter.
Ce n'est pas très visible dans la documentation officielle, mais il est indiqué que, par défaut, MongoDB annulera toute transaction durant plus de 60 secondes afin d'éviter de bloquer la base pendant trop longtemps.
Les solutions
Vérifier que votre transaction n'est pas bloquée
En effet, si jamais il y a un problème dans votre code logique et que l'exécution ou l'enchainement des opération est bloqué, alors MongoDB stoppera tout simplement la transaction en question.
Vous pouvez alors vérifier l'exécution de chaque opération en dehors de votre transaction pour vérifier que tout fonctionne correctement.
Réduire le temps d'exécution
Il se peut que vous ayez tellement d'opérations à effectuer sur la base de données au sein de votre transaction que le temps d'exécution total dépasse simplement le timeout par défaut de MongoDB.
La meilleure solution sera alors de trouver un moyen pour faire en sorte que votre transaction mette moins de temps à s'exécuter.
Si vous utilisez NodeJS, l'une des clés de solutions si vous bouclez sur beaucoup de données que peut être de remplacer des appels async/await par un Promise.all comme expliqué dans cet article.
Modifier la configuration de MongoDB
Si jamais vos contraintes métier vous obligent à concevoir une transaction qui dépasse le timeout par défaut de 60 secondes (ce qui n'est pas recommandé), alors la dernière solution sera de modifier la configuration de la base pour augmenter le temps autorisé pour une transaction :
db.adminCommand( { setParameter: 1, transactionLifetimeLimitSeconds: 90 } )
Pour plus d'informations, je vous invite à lire la documentation officielle sur les transactions : https://docs.mongodb.com/manual/core/transactions-sharded-clusters/
Aucun commentaire pour l'instant