Règle
Libération blocage même sur d'exception d'exception.
Chaque verrouillage acquisition doit avoir a garantie
garantie, même lorsque exceptions se produisent.
Langues pris en charge:** Java, C, C++, PHP, JavaScript,
TypeScript, Go, PythonIntroduction
Les verrous non libérés sont l'une des causes les plus courantes de blocages (deadlocks) et de plantages système dans les applications Node.js en production. Lorsqu'une exception se produit entre l'acquisition et la libération d'un verrou, celui-ci reste détenu indéfiniment. D'autres opérations asynchrones attendant ce verrou restent bloquées pour toujours, provoquant des défaillances en cascade à travers le système. Un seul mutex non libéré peut faire tomber une API entière car la boucle d'événements est bloquée et les requêtes s'accumulent. Cela se produit avec des bibliothèques comme async-mutex, mutexify, ou toute implémentation manuelle de verrouillage où la libération n'est pas automatique.
Pourquoi c'est important
Stabilité et disponibilité du système : Les verrous non libérés provoquent des interblocages qui figent les opérations asynchrones dans Node.js. Dans les serveurs Express ou Fastify, cela épuise les workers disponibles, rendant l'application incapable de gérer de nouvelles requêtes. La seule solution est de redémarrer le processus, ce qui entraîne des temps d'arrêt. Dans les architectures de microservices, les verrous non libérés dans un service peuvent provoquer des défaillances en cascade dans les services dépendants, car ils expirent en attendant des réponses.
Dégradation des performances: Avant un blocage complet (deadlock), les verrous non libérés entraînent de graves problèmes de performance. Les opérations asynchrones se disputent les ressources verrouillées, créant une file d'attente de promesses en attente qui ne se résolvent jamais. La contention des verrous crée des pics de latence imprévisibles qui dégradent l'expérience utilisateur. À mesure que le nombre de requêtes concurrentes augmente sous charge, la contention s'aggrave de manière exponentielle.
Complexité du débogage : Les interblocages (deadlocks) dus à des verrous non libérés sont notoirement difficiles à déboguer dans les applications Node.js en production. Les symptômes apparaissent loin de la cause première, les blocages de processus montrent des promesses en attente mais pas quel chemin d'exception n'a pas réussi à libérer le verrou. Reproduire la séquence exacte d'exceptions qui a déclenché l'interblocage est souvent impossible dans les environnements de développement.
Épuisement des ressources : Au-delà des verrous eux-mêmes, l'incapacité à libérer les verrous est souvent corrélée à l'incapacité à libérer d'autres ressources comme les connexions de base de données, les clients Redis ou les descripteurs de fichiers. Cela aggrave le problème, créant de multiples fuites de ressources qui font tomber les systèmes plus rapidement sous charge.
Exemples de code
❌ Non conforme :
const { Mutex } = require('async-mutex');
const accountMutex = new Mutex();
async function transferFunds(from, to, amount) {
await accountMutex.acquire();
if (from.balance < amount) {
throw new Error('Insufficient funds');
}
from.balance -= amount;
to.balance += amount;
accountMutex.release();
}
Pourquoi c'est dangereux : Si l'erreur de fonds insuffisants est levée, accountMutex.release() ne s'exécute jamais et le mutex reste verrouillé indéfiniment. Tous les appels ultérieurs à transferFunds() se bloquera en attendant le mutex, gelant l'ensemble du système de paiement.
✅ Conforme :
const { Mutex } = require('async-mutex');
const accountMutex = new Mutex();
async function transferFunds(from, to, amount) {
const release = await accountMutex.acquire();
try {
if (from.balance < amount) {
throw new Error('Insufficient funds');
}
from.balance -= amount;
to.balance += amount;
} catch (error) {
logger.error('Transfer failed', {
fromId: from.id,
toId: to.id,
amount,
error: error.message
});
throw error;
} finally {
release();
}
}Pourquoi c'est sûr : Le Détecter Le bloc enregistre l'erreur avec son contexte avant de la relancer, et le finally Le bloc garantit que la fonction de libération du mutex s'exécute, que l'opération réussisse, qu'elle lève une erreur, ou que l'erreur soit relancée depuis le bloc catch. Le verrou est toujours libéré, ce qui empêche les interblocages.
Conclusion
La libération du verrou doit être garantie, et non conditionnelle à une exécution réussie. Utilisez try-finally blocs en JavaScript ou le runExclusive() utilitaire fourni par des bibliothèques telles que async-mutex. Chaque acquisition de verrouillage devrait avoir un chemin de libération inconditionnel visible dans le même bloc de code. Une gestion appropriée des verrous n'est pas facultative, c'est la différence entre un système stable et un système qui se bloque aléatoirement sous charge.
.avif)
