2016-02-14 13 views
22

प्राप्त करने के लिए अनुरोध करें मॉड्यूल के साथ async मॉड्यूल के संयोजन के साथ समानांतर में कई लिंक क्रॉल कर रहा हूं।
मैं ETIMEDOUT और ESOCKETTIMEDOUT त्रुटियों के बहुत से देख रहा हूं हालांकि लिंक पहुंच योग्य हैं और क्रोम का उपयोग करके काफी तेज़ी से प्रतिक्रिया देते हैं।Node.js अनुरोध मॉड्यूल ETIMEDOUT और ESOCKETTIMEDOUT

मैंने अनुरोध विकल्पों में maxSockets से 2 और timeout से 10000 तक सीमित कर दिया है। मैं async.filterLimit() का उपयोग कर 2 की सीमा के साथ 2 बार प्रत्येक समानता को समानांतरता में कटौती करने के लिए उपयोग कर रहा हूं। तो मेरे पास सर्वर से शीर्षलेख प्रतिक्रिया की प्रतीक्षा करने के लिए 2 सॉकेट, 2 अनुरोध, और 10 सेकंड का टाइमआउट है, फिर भी मुझे ये त्रुटियां मिलती हैं।

यहाँ

की अनुरोध विन्यास मैं का उपयोग करें:

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

यहाँ कोड का स्निपेट मैं लिंक fecth करने के लिए उपयोग:

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); 
    }); 

मैं त्रुटि घटना को सुना और मैं देख रहा हूँ कि जब भी त्रुटि कोड ETIMEDOUT कनेक्ट ऑब्जेक्ट या तो सत्य/गलत है, इसलिए कभी-कभी यह एक कनेक्शन टाइमआउट होता है और कभी-कभी यह नहीं होता है (अनुरोध डॉक्स के अनुसार)

अद्यतन:

pool: { 
    maxSockets: Infinity 
} 

में आदेश बैंडविड्थ नियंत्रित करने के लिए मैं कार्यान्वित एक requestLoop विधि है कि अनुरोध को पूरा: मैं उपलब्ध सॉकेट की कमी के कारण maxSocketsInfinity ताकि कोई संबंध नहीं hangup किया जाएगा अप को बढ़ावा देने का फैसला किया

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); 
    }); 

requestLoop का कार्यान्वयन:

एक maxAttemps और retryDelay मानकों के साथ अनुरोध को नियंत्रित करने के 0
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); 
      } 
     }); 
    } 
}; 

तो यह यह योग करने के लिए ऊपर: - बढ़ाया Infinity को maxSockets सॉकेट कनेक्शन की टाइमआउट त्रुटि को दूर करने की कोशिश करने के लिए - असफल अनुरोध और maxAttemps के साथ ही इस तरह के अनुरोध की retryDelay नियंत्रित करने के लिए Implemnted requestLoop विधि - इसके अलावा maxium संख्या नहीं है async.filterLimit

पर हस्ताक्षर किए गए समवर्ती अनुरोध के अनुसार मैं यह ध्यान रखना चाहता हूं कि मैंने त्रुटियों को मुक्त क्रॉल करने के लिए यहां सबकुछ की सेटिंग्स के साथ भी खेला है लेकिन अब तक प्रयास विफल रहे हैं।

अभी भी इस समस्या को हल करने के बारे में मदद की तलाश में है।

UPDATE2: मैंने async.filterLimit को छोड़ने और अपनी खुद की सीमा तंत्र बनाने का निर्णय लिया है। मैं बस मुझे इस लक्ष्य को हासिल करने में मदद करने के लिए 3 चर है:
pendingRequests - एक अनुरोध सरणी जो सभी अनुरोधों का आयोजन करेगा (जो बाद में समझा जाएगा) activeRequests - सक्रिय अनुरोधों की संख्या maxConcurrentRequests - अधिकतम स्वीकृत समवर्ती अनुरोधों की संख्या

में pendingRequests सरणी, मैं साथ ही एक जटिल requestLoop समारोह के लिए एक संदर्भ युक्त वस्तु धक्का के रूप में तर्क तर्क युक्त सरणी पाश समारोह को पास करने की:

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(); 

आप '' कॉल नोटिस अंत में runRequest() पर। इस समारोह काम अनुरोध और आग अनुरोध जब जबकि maxConcurrentRequests की सीमा के अंतर्गत अधिकतम activeRequests रखने यह कर सकते हैं का प्रबंधन करने के लिए है:

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(); 
    }); 

यह यद्यपि मेरी testings के माध्यम से, किसी भी टाइमआउट त्रुटियों का समाधान करना चाहिए, मैं अभी भी ध्यान दिया है विशिष्ट वेबसाइटों में कुछ टाइमआउट मैंने इसका परीक्षण किया है। मैं इस बारे में 100% निश्चित नहीं हो सकता, लेकिन मुझे लगता है कि यह आईपी-जांच करके अधिकतम उपयोगकर्ता अनुरोधों को सीमित करने वाली वेबसाइट की प्रकृति के कारण है और परिणामस्वरूप कुछ HTTP 400 संदेश लौटा रहा है सर्वर पर संभावित 'हमले' को रोकने के लिए।

+0

क्या आपको कभी यह पता चला है कि @ जोरायन? – DvideBy0

+0

मान लीजिए, कभी-कभी ऐसी ही समस्या है – Denny

+0

@ DvideBy0 ने एक समाधान अद्यतन किया – Jorayen

उत्तर

19

संपादित करें: https://stackoverflow.com/a/37946324/744276

की डुप्लीकेट डिफ़ॉल्ट रूप से, नोड 4 workers to resolve DNS queries है। यदि आपकी DNS क्वेरी लंबे समय तक आती है, तो अनुरोध DNS चरण पर अवरुद्ध हो जाएंगे, और लक्षण बिल्कुल ESOCKETTIMEDOUT या ETIMEDOUT है।

थ्रेड पूल अपने यूवी आकार में वृद्धि का प्रयास करें:

export UV_THREADPOOL_SIZE=128 
node ... 

या index.js में (या जहाँ भी अपने प्रवेश बिंदु है):

#!/usr/bin/env node 
process.env.UV_THREADPOOL_SIZE = 128; 

function main() { 
    ... 
} 

I reproduced this locally टीसी का उपयोग कर DNS सर्वर से प्रतिक्रियाओं को धीमा द्वारा।

+0

इस विषय के सहायक जोड़े के लिए धन्यवाद, मैंने अभी तक परीक्षण किया है कि आपने जो सुझाव दिया है, लेकिन यह अच्छा है कम से कम कोई नहीं जानता।जैसे ही मेरे पास ऐसा करने के लिए एक खाली समय होगा, मैं परिणाम की रिपोर्ट भी करूंगा :) – Jorayen

+0

मैंने यूवी_THREADPOOL_SIZE के बारे में जो पढ़ा है, वह सुझाव देता है कि यह आईओ (जैसे डिस्क एक्सेस) को अवरुद्ध करने के लिए सबसे महत्वपूर्ण है लेकिन गैर- अवरुद्ध आईओ (जैसे नेटवर्क एक्सेस)। – Eric

0

मुझे पता चला कि बहुत सारे एसिंक अनुरोध हैं, तो लिनक्स में ESOCKETTIMEDOUT अपवाद होता है। अनुरोध करने के लिए() इस सेटिंग विकल्पों

: वैकल्पिक हल मैंने पाया यह क्या कर रही है agent: false, pool: {maxSockets: 100} सूचना है कि उसके बाद, टाइमआउट ताकि आप झूठ बोल रही है किया जा सकता है हो सकता है यह वृद्धि की जरूरत है।

संबंधित मुद्दे