visual studio nodejs node handling guide error documentación diccionario debug code node.js sockets asynchronous request httprequest

node.js - studio - node js server



El módulo de solicitud de Node.js obtiene ETIMEDOUT y ESOCKETTIMEDOUT (2)

Estoy rastreando una gran cantidad de enlaces con el módulo de request en paralelo con la combinación del módulo async .
Estoy notando muchos errores de ETIMEDOUT y ESOCKETTIMEDOUT aunque los enlaces son alcanzables y responden bastante rápido usando chrome.

maxSockets a 2 y el timeout de timeout a 10000 en las opciones de solicitud. Estoy usando async.filterLimit() con un límite de 2 para incluso reducir el paralelismo a 2 solicitudes cada vez. Así que tengo 2 sockets, 2 request y un tiempo de espera de 10 segundos para esperar la respuesta de los encabezados del servidor, pero recibo estos errores.

Aquí, la configuración de solicitud que uso:

{ ... pool: { maxSockets: 2 }, timeout: 10000 , time: true ... }

Aquí está el fragmento de código que utilizo para formar enlaces:

var self = this; async.filterLimit(resources, 2, function(resource, callback) { request({ uri: resource.uri }, function (error, response, body) { if (!error && response.statusCode === 200) { ... } else { self.emit(''error'', resource, error); } callback(...); }) }, function(result) { callback(null, result); });

Escuché el evento de error y veo cada vez que el código de error es ETIMEDOUT el objeto de conexión es verdadero / falso, por lo que a veces es un tiempo de espera de conexión y, a veces, no lo es (según los documentos de solicitud)

ACTUALIZACIÓN: decidí aumentar los maxSockets a Infinity para que no se maxSockets conexiones debido a la falta de enchufes disponibles:

pool: { maxSockets: Infinity }

Para controlar el ancho de banda, implementé un método requestLoop que maneja la solicitud con los parámetros maxAttemps y retryDelay para controlar las solicitudes:

async.filterLimit(resources, 10, function(resource, callback) { self.requestLoop({ uri: resource.uri }, 100, 5000, function (error, response, body) { var fetched = false; if (!error) { ... } else { .... } callback(...); }); }, function(result) { callback(null, result); });

Implementación de requestLoop:

requestLoop = function(options, attemptsLeft, retryDelay, callback, lastError) { var self = this; if (attemptsLeft <= 0) { callback((lastError != null ? lastError : new Error(''...''))); } else { request(options, function (error, response, body) { var recoverableErrors = [''ESOCKETTIMEDOUT'', ''ETIMEDOUT'', ''ECONNRESET'', ''ECONNREFUSED'']; var e; if ((error && _.contains(recoverableErrors, error.code)) || (response && (500 <= response.statusCode && response.statusCode < 600))) { e = error ? new Error(''...''); e.code = error ? error.code : response.statusCode; setTimeout((function () { self.requestLoop(options, --attemptsLeft, retryDelay, callback, e); }), retryDelay); } else if (!error && (200 <= response.statusCode && response.statusCode < 300)) { callback(null, response, body); } else if (error) { e = new Error(''...''); e.code = error.code; callback(e); } else { e = new Error(''...''); e.code = response.statusCode; callback(e); } }); } };

Así que para resumir: - maxSockets a Infinity para intentar superar el error de tiempo de espera de la conexión de sockets - Implementé el método requestLoop para controlar la solicitud fallida y maxAttemps , así como retryDelay de dichas solicitudes - También hay un número máximo de solicitud simultánea establecida por el número pasado para async.filterLimit

Quiero señalar que también he jugado con la configuración de todo aquí para obtener errores en el rastreo libre, pero hasta ahora los intentos han fallado.

Todavía estoy buscando ayuda para resolver este problema.

ACTUALIZACIÓN2: he decidido eliminar async.filterLimit y crear mi propio mecanismo de límite. Solo tengo 3 variables para ayudarme a lograr esto:
pendingRequests - una matriz de solicitud que contendrá todas las solicitudes (se explicará más adelante) activeRequests - número de solicitudes activas maxConcurrentRequests - número de solicitudes simultáneas permitidas máximas

en la matriz pendingRequests, presiono un objeto complejo que contiene una referencia a la función requestLoop y una matriz de argumentos que contiene los argumentos que se pasarán a la función de bucle:

self.pendingRequests.push({ "arguments": [{ uri: resource.uri.toString() }, self.maxAttempts, function (error, response, body) { if (!error) { if (self.policyChecker.isMimeTypeAllowed((response.headers[''content-type''] || '''').split('';'')[0]) && self.policyChecker.isFileSizeAllowed(body)) { self.totalBytesFetched += body.length; resource.content = self.decodeBuffer(body, response.headers["content-type"] || '''', resource); callback(null, resource); } else { self.fetchedUris.splice(self.fetchedUris.indexOf(resource.uri.toString()), 1); callback(new Error(''Fetch failed because a mime-type is not allowed or file size is bigger than permited'')); } } else { self.fetchedUris.splice(self.fetchedUris.indexOf(resource.uri.toString()), 1); callback(error); } self.activeRequests--; self.runRequest(); }], "function": self.requestLoop }); self.runRequest();

Notará la llamada a runRequest() al final. El trabajo de esta función es administrar las solicitudes y disparar las solicitudes cuando puede, manteniendo las activeRequests máximas activeRequests debajo del límite de maxConcurrentRequests :

var self = this; process.nextTick(function() { var next; if (!self.pendingRequests.length || self.activeRequests >= self.maxConcurrentRequests) { return; } self.activeRequests++; next = self.pendingRequests.shift(); next["function"].apply(self, next["arguments"]); self.runRequest(); });

Esto debería resolver cualquier error de Tiempo de espera, a través de mis pruebas, sin embargo, todavía he notado algunos tiempos de espera en sitios web específicos en los que he probado esto. No puedo estar 100% seguro de esto, pero creo que es debido a la naturaleza del sitio web que respalda el servidor http que limita al máximo las solicitudes de un usuario al realizar una comprobación de IP y, como resultado, devuelve algunos mensajes de HTTP 400 para evitar un posible ''ataque'' en el servidor.


Descubrí que si hay demasiadas solicitudes de sincronización, la excepción ESOCKETTIMEDOUT ocurre en Linux. La solución alternativa que he encontrado es hacer esto:

estableciendo estas opciones para request (): agent: false, pool: {maxSockets: 100} Tenga en cuenta que después de eso, el tiempo de espera puede estar mintiendo, por lo que es posible que necesite aumentarlo.


Editar: duplicado de https://.com/a/37946324/744276

Por defecto, Node tiene 4 trabajadores para resolver consultas DNS . Si su consulta de DNS tarda mucho tiempo, las solicitudes se bloquearán en la fase de DNS, y el síntoma es exactamente ESOCKETTIMEDOUT o ETIMEDOUT .

Intente aumentar el tamaño de su agrupación de subprocesos uv:

export UV_THREADPOOL_SIZE=128 node ...

o en index.js (o donde sea que esté su punto de entrada):

#!/usr/bin/env node process.env.UV_THREADPOOL_SIZE = 128; function main() { ... }

Reproduje esto localmente al ralentizar las respuestas del servidor DNS usando tc.