1k HTTP रिक्वेस्ट के समानांतर ट्रिगर अटक जाता


10

सवाल यह है कि जब आप 1k-2k निवर्तमान HTTP अनुरोधों को ट्रिगर करते हैं तो वास्तव में क्या हो रहा है? मैं देखता हूं कि यह 500 कनेक्शनों के साथ सभी कनेक्शनों को आसानी से हल कर देगा, लेकिन वहां से आगे बढ़ने से समस्या पैदा होती है क्योंकि कनेक्शन खुले रहते हैं और नोड ऐप वहां अटक जाएगा। स्थानीय सर्वर + उदाहरण Google और अन्य नकली सर्वर के साथ परीक्षण किया गया।

इसलिए कुछ अलग सर्वर एंडपॉइंट के साथ मुझे कारण प्राप्त हुआ: ECONNRESET पढ़ें जो ठीक है कि सर्वर अनुरोध को संभाल नहीं सका और एक त्रुटि फेंक सकता है। 1k-2k अनुरोध में कार्यक्रम बस लटका रहेगा। जब आप खुले कनेक्शनों की जांच करते हैं, lsof -r 2 -i -aतो आप देख सकते हैं कि कुछ एक्स कनेक्शन हैं जो वहां लटके रहते हैं 0t0 TCP 192.168.0.20:54831->lk-in-f100.1e100.net:https (ESTABLISHED)। जब आप अनुरोध करने के लिए टाइमआउट सेटिंग जोड़ते हैं, तो यह संभवत: टाइमआउट त्रुटि के साथ समाप्त हो जाएगा, लेकिन अन्यथा कनेक्शन हमेशा के लिए रखा जाता है और मुख्य कार्यक्रम कुछ लिम्बो स्थिति में समाप्त हो जाएगा?

उदाहरण कोड:

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

1
क्या आप इसका परिणाम पोस्ट कर सकते हैं npx envinfo, अपना उदाहरण मेरे विन १० / नोड १०.१६.० पर स्क्रिप्ट चलाकर .80४३२.5०५ सेंटीमीटर में समाप्त होता है
Łukasz Szewczak

मैं ओएस एक्स और अल्पाइन लिनक्स (डॉकटर कंटेनर) पर उदाहरण चलाता हूं और उसी परिणाम पर पहुंचा हूं।
रिस्तो नोविक

मेरा स्थानीय मैक 7156.797ms में स्क्रिप्ट चलाता है। क्या आप सुनिश्चित हैं कि अनुरोधों को अवरुद्ध करने वाले कोई फ़ायरवॉल नहीं हैं?
जॉन

स्थानीय मशीन फ़ायरवॉल का उपयोग किए बिना परीक्षण किया गया, लेकिन क्या यह मेरे स्थानीय राउटर / नेटवर्क के साथ कोई समस्या हो सकती है? मैं Google क्लाउड या हरोकू में एक समान परीक्षण चलाने की कोशिश करूंगा।
रिस्तो नोविक

जवाबों:


3

यह सुनिश्चित करने के लिए कि क्या हो रहा था, मुझे आपकी पटकथा में कुछ संशोधन करने की आवश्यकता थी, लेकिन यहाँ हैं।

सबसे पहले, आप जानते हैं कि कैसे nodeऔर इसके event loopकाम करता है, लेकिन मुझे एक त्वरित पुनर्कथन करना चाहिए। जब आप कोई स्क्रिप्ट चलाते हैं, तो nodeरनटाइम पहले उसके समकालिक भाग को चलाता है, फिर शेड्यूल करता है promisesऔर timersअगले लूप्स पर निष्पादित किया जाता है, और जब उन्हें चेक किया जाता है, तो दूसरे लूप में कॉलबैक चलाएं। यह सरल सार यह बहुत अच्छी तरह से समझाता है, @StephenGrider को श्रेय:


const pendingTimers = [];
const pendingOSTasks = [];
const pendingOperations = [];

// New timers, tasks, operations are recorded from myFile running
myFile.runContents();

function shouldContinue() {
  // Check one: Any pending setTimeout, setInterval, setImmediate?
  // Check two: Any pending OS tasks? (Like server listening to port)
  // Check three: Any pending long running operations? (Like fs module)
  return (
    pendingTimers.length || pendingOSTasks.length || pendingOperations.length
  );
}

// Entire body executes in one 'tick'
while (shouldContinue()) {
  // 1) Node looks at pendingTimers and sees if any functions
  // are ready to be called.  setTimeout, setInterval
  // 2) Node looks at pendingOSTasks and pendingOperations
  // and calls relevant callbacks
  // 3) Pause execution. Continue when...
  //  - a new pendingOSTask is done
  //  - a new pendingOperation is done
  //  - a timer is about to complete
  // 4) Look at pendingTimers. Call any setImmediate
  // 5) Handle any 'close' events
}

// exit back to terminal

ध्यान दें कि जब तक लंबित ओएस कार्य नहीं होता है तब तक ईवेंट लूप कभी समाप्त नहीं होगा। दूसरे शब्दों में, जब तक HTTP अनुरोध लंबित नहीं होंगे, तब तक आपका नोड निष्पादन कभी समाप्त नहीं होगा।

आपके मामले में, यह एक asyncफ़ंक्शन चलाता है, क्योंकि यह हमेशा एक वादा वापस करेगा, यह इसे अगले लूप पुनरावृत्ति में निष्पादित करने के लिए शेड्यूल करेगा। अपने async फ़ंक्शन पर, आप उस पुनरावृत्ति में एक बार में 1000 अन्य वादे (HTTP अनुरोध) निर्धारित करते हैं map। उसके बाद, आप सभी का इंतजार कर रहे हैं फिर कार्यक्रम समाप्त करने का संकल्प लें। यह तब तक काम करेगा, जब तक कि आपके अनाम तीर पर mapकोई भी त्रुटि न आए । यदि आपका कोई वादा एक त्रुटि फेंकता है और आप उसे संभालते नहीं हैं, तो कुछ वादों में उनका कॉलबैक नहीं होगा, जिसे कभी भी समाप्त होने का कार्यक्रम बनाने के लिए कहा जाता है , लेकिन बाहर निकलने के लिए नहीं , क्योंकि इवेंट लूप इसे हल होने तक बाहर निकलने से रोक देगा। कॉलबैक के बिना भी सभी कार्य। जैसा कि यह कहता हैPromise.all डॉक्स : पहला वादा खारिज होते ही इसे अस्वीकार कर दिया जाएगा।

तो, आपकी ECONNRESETत्रुटि स्वयं नोड से संबंधित नहीं है, आपके नेटवर्क के साथ कुछ है जिसने त्रुटि को फेंकने के लिए भ्रूण बनाया और फिर इवेंट लूप को समाप्त होने से रोक दिया। इस छोटे से सुधार के साथ, आप सभी अनुरोधों को एसिंक्रोनस रूप से हल करते हुए देख पाएंगे:

const fetch = require("node-fetch");

(async () => {
  try {
    const promises = Array(1000)
      .fill(1)
      .map(async (_value, index) => {
        try {
          const url = "https://google.com/";
          const response = await fetch(url);
          console.log(index, response.statusText);
          return response;
        } catch (e) {
          console.error(index, e.message);
        }
      });
    await Promise.all(promises);
  } catch (e) {
    console.error(e);
  } finally {
    console.log("Done");
  }
})();

अरे, पेड्रो समझाने के प्रयास के लिए धन्यवाद। मुझे पता है कि Promise.all अस्वीकार होगा जब पहला वादा अस्वीकृति प्रकट होती है, लेकिन ज्यादातर मामलों में अस्वीकार करने के लिए कोई त्रुटि नहीं थी, इसलिए पूरी बात सिर्फ बेकार होगी।
रिस्तो नोविक

1
> यह दोहराता है कि जब तक लंबित ओएस कार्य नहीं होगा, इवेंट लूप कभी समाप्त नहीं होगा। दूसरे शब्दों में, जब तक HTTP अनुरोध लंबित नहीं होंगे, तब तक आपका नोड निष्पादन कभी समाप्त नहीं होगा। यह एक दिलचस्प बिंदु लगता है, ओएस कार्यों को लिबव के माध्यम से प्रबंधित किया जाता है?
रिस्तो नोविक

मुझे लगता है कि लीब्यूव संचालन से जुड़ी अधिक चीजों को संभालता है (ऐसी चीजें जिन्हें वास्तव में मल्टी-थ्रेडिंग की आवश्यकता होती है)। लेकिन मैं गलत हो सकता है, अधिक गहराई से देखने की आवश्यकता है
पेड्रो मटेर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.