A questão é o que realmente está acontecendo quando você aciona solicitações HTTP de saída de 1 a 2k? Vejo que resolveria todas as conexões facilmente com 500 conexões, mas subir de lá parece causar problemas, pois as conexões são deixadas abertas e o aplicativo Node fica preso lá. Testado com servidor local + exemplo Google e outros servidores simulados.
Portanto, com alguns pontos de extremidade do servidor diferentes , recebi o motivo: leia ECONNRESET, o que é bom, o servidor não pode lidar com a solicitação e gera um erro. No intervalo de solicitação de 1k a 2k, o programa seria interrompido. Ao verificar as conexões abertas, lsof -r 2 -i -a
você pode ver que há uma quantidade X de conexões que continuam penduradas lá 0t0 TCP 192.168.0.20:54831->lk-in-f100.1e100.net:https (ESTABLISHED)
. Quando você adiciona a configuração de tempo limite às solicitações, elas provavelmente acabam com erro de tempo limite, mas por que, de outro modo, a conexão é mantida para sempre e o programa principal terminaria em algum estado limbo?
Código de exemplo:
import fetch from 'node-fetch';
(async () => {
const promises = Array(1000).fill(1).map(async (_value, index) => {
const url = 'https://google.com';
const response = await fetch(url, {
// timeout: 15e3,
// headers: { Connection: 'keep-alive' }
});
if (response.statusText !== 'OK') {
console.log('No ok received', index);
}
return response;
})
try {
await Promise.all(promises);
} catch (e) {
console.error(e);
}
console.log('Done');
})();
fonte
npx envinfo
exemplo, executando o seu exemplo no meu script Win 10 / nodev10.16.0, que termina em 8432.805msRespostas:
Para entender o que estava acontecendo com certeza, eu precisava fazer algumas modificações no seu script, mas aqui estão elas.
Primeiro, você pode saber como
node
e comoevent loop
funciona, mas deixe-me fazer uma rápida recapitulação. Quando você executar um script,node
tempo de execução primeiro executar a parte síncrona de que, em seguida, agendar opromises
etimers
a ser executado nos próximos loops, e quando verificado que eles são resolvidos, execute os retornos de chamada em outro loop. Esta essência simples explica muito bem, crédito para @StephenGrider:No seu caso, ele executa uma
async
função, pois sempre retornará uma promessa, agendará para que seja executada na próxima iteração do loop. Na sua função assíncrona, você agenda outras 1000 promessas (solicitações HTTP) de uma só vez nessamap
iteração. Depois disso, você está aguardando que seja resolvido para concluir o programa. Funcionará, com certeza, a menos que sua seta anônima funcione no erromap
não aconteça . Se uma das suas promessas gerar um erro e você não lidar com elas, algumas delas não terão seu retorno de chamada chamado, fazendo com que o programa termine, mas não saia , porque o loop de eventos impedirá que ele saia até que seja resolvido todas as tarefas, mesmo sem retorno de chamada. Como diz noPromise.all
docs : rejeitará assim que a primeira promessa rejeitar.Portanto, seu
ECONNRESET
erro on não está relacionado ao nó em si, é algo com a sua rede que fez a busca para lançar um erro e impedir que o loop de eventos termine. Com essa pequena correção, você poderá ver todos os pedidos sendo resolvidos de forma assíncrona:fonte