Regra
Libertação fechaduras mesmo em exceção caminhos.
Todos os bloqueio aquisição deve ter a garantida
libertação, mesmo quando excepções ocorrem.
Suportados linguagens suportadas:** Java, C, C++, PHP, JavaScript,
TypeScript, Go, PythonIntrodução
Os bloqueios não liberados são uma das causas mais comuns de deadlocks e travamentos do sistema em aplicativos Node.js de produção. Quando ocorre uma exceção entre a aquisição e a liberação do bloqueio, o bloqueio permanece retido indefinidamente. Outras operações assíncronas que esperam por esse bloqueio ficam suspensas para sempre, causando falhas em cascata em todo o sistema. Um único mutex não liberado pode derrubar uma API inteira porque o loop de eventos fica bloqueado e as solicitações se acumulam. Isso acontece com bibliotecas como async-mutex, mutexificarou qualquer aplicação de bloqueio manual em que o desbloqueio não seja automático.
Porque é importante
Estabilidade e disponibilidade do sistema: Os bloqueios não liberados causam deadlocks que congelam as operações assíncronas no Node.js. Em servidores Express ou Fastify, isso esgota os trabalhadores disponíveis, tornando o aplicativo incapaz de lidar com novas solicitações. A única recuperação é reiniciar o processo, causando tempo de inatividade. Em arquitecturas de microsserviços, os bloqueios não libertados num serviço podem provocar falhas em cascata nos serviços dependentes, uma vez que estes ficam à espera de respostas.
Degradação do desempenho: Antes do deadlock completo, os bloqueios não liberados causam graves problemas de desempenho. As operações assíncronas disputam os recursos bloqueados, criando uma fila de promessas pendentes que nunca são resolvidas. A contenção de bloqueios cria picos de latência imprevisíveis que degradam a experiência do utilizador. À medida que o número de pedidos simultâneos aumenta sob carga, a contenção aumenta exponencialmente.
Complexidade de depuração: Deadlocks de bloqueios não liberados são notoriamente difíceis de depurar em aplicações Node.js de produção. Os sintomas parecem distantes da causa raiz, as interrupções do processo mostram promessas pendentes, mas não qual caminho de exceção falhou ao liberar o bloqueio. Reproduzir a sequência exata de exceções que desencadeou o deadlock geralmente é impossível em ambientes de desenvolvimento.
Exaustão de recursos: Além dos bloqueios em si, a falha na liberação de bloqueios geralmente está correlacionada com a falha na liberação de outros recursos, como conexões de banco de dados, clientes Redis ou manipuladores de arquivos. Isso agrava o problema, criando vários vazamentos de recursos que derrubam os sistemas mais rapidamente sob carga.
Exemplos de código
Não 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();
}
Porque é que não é seguro: Se o erro de fundos insuficientes for lançado, accountMutex.release() nunca é executada e o mutex permanece bloqueado para sempre. Todas as chamadas subsequentes a transferFunds() ficará suspenso à espera do mutex, congelando todo o sistema de pagamento.
Conformidade:
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();
}
}Porque é que é seguro: O captura regista o erro com contexto antes de o voltar a lançar, e o bloco finalmente garante que a função de libertação do mutex é executada, quer a operação seja bem sucedida, quer lance um erro, quer o erro seja novamente lançado a partir de catch. O bloqueio é sempre libertado, evitando bloqueios.
Conclusão
A libertação do cadeado deve ser garantida e não condicionada a uma execução bem sucedida. Utilização tentar-finalmente em JavaScript ou o bloco runExclusive() fornecido por bibliotecas como async-mutex. Cada aquisição de bloqueio deve ter um caminho de libertação incondicional visível no mesmo bloco de código. O gerenciamento adequado de bloqueios não é opcional, é a diferença entre um sistema estável e um que trava aleatoriamente sob carga.
.avif)
