क्या आपने कभी किसी को अपने टेस्ट्स के बहुत तेज़ होने की शिकायत करते सुना है? मैं भी नहीं।
तेज़ टेस्ट्स का अर्थ है तेज़ फीडबैक। चाहे आप उन्हें स्थानीय रूप से चलाएं या एक सतत एकीकरण पाइपलाइन में, आपके टेस्ट्स जितनी जल्दी खत्म होंगे, आप विफलताओं पर प्रतिक्रिया दे सकते हैं और अपने कोड में सुधार कर सकते हैं। उत्पादकता लाभ के अलावा, यह सर्वविदित है कि धीमे टेस्ट्स डेवलपर्स को चिड़चिड़ा बना देते हैं। किसी को अपने डेवलपर्स का चिड़चिड़ा होना पसंद नहीं।
यह सब कहा जाने के साथ, एक बिजली-तेज़ टेस्ट सूट बनाना हमेशा उतना आसान नहीं होता जितना आप आशा करेंगे। सौभाग्य से, रेल्स 6 ने समानांतर टेस्टिंग नामक एक रोमांचक सुविधा पेश की। इसके साथ शुरुआत करना सहज है और यह आपके टेस्ट्स को बहुत तेज़ कर सकता है। हालांकि, कुछ नुकसान हैं जिनसे सावधान रहना चाहिए।
समानांतर टेस्टिंग क्या है?
समानांतर टेस्टिंग का वास्तव में क्या मतलब है?
जब आप एक टेस्ट सूट चलाते हैं, तो आपका टेस्ट रनर आमतौर पर आपके टेस्ट्स को एक के बाद एक - या सीरियली - निष्पादित करने के लिए एक सिंगल प्रोसेस स्पॉन करेगा। एक सिंगल टेस्ट प्रोसेस एक सिंगल CPU कोर का उपयोग करता है। जैसा कि आप शायद कल्पना कर सकते हैं, यह दृष्टिकोण आधुनिक हार्डवेयर का पूरा लाभ नहीं लेता, जिसमें अक्सर दर्जनों CPU कोर होते हैं।
आपके पास 10 CPU कोर वाला एक फैंसी मैकबुक हो सकता है, लेकिन दुख की बात है कि यह आपके टेस्ट्स को तेज़ नहीं करेगा!
हम व्यक्तिगत टेस्ट्स को कई वर्कर प्रोसेस में वितरित करके इसे बदल सकते हैं। टेस्ट्स अब एक-दूसरे के बाद नहीं चलेंगे, बल्कि एक-दूसरे के बगल में - समानांतर में। दो वर्कर्स पर अपना टेस्ट सूट चलाना एक वर्कर पर उसी टेस्ट सूट को चलाने से दोगुना तेज़ है।
आपकी मशीन में जितने अधिक कोर होंगे, उतने अधिक वर्कर प्रोसेस संभव होंगे, और इस प्रकार, आपका टेस्ट सूट उतनी ही तेज़ी से खत्म होगा। मान लीजिए आपके टेस्ट्स आमतौर पर आठ मिनट में चलते हैं। उन्हीं टेस्ट्स को चार वर्कर प्रोसेस का उपयोग करके चलाने से रनटाइम लगभग दो मिनट तक कम हो जाएगा!
एक अच्छे 16 कोर मशीन पर ऐसा करने की कल्पना करें, जहां हम सोलह वर्कर्स स्पॉन कर सकते हैं। बहुत अच्छा!
रेल्स में समानांतर टेस्टिंग कॉन्फ़िगर करना
तो हम वहां कैसे पहुंचते हैं? हाल तक, आप अपने टेस्ट सूट को समानांतर करने के लिए थर्ड-पार्टी जेम्स का उपयोग कर सकते थे, लेकिन रेल्स 6 से शुरू होकर, समानांतर टेस्ट मानक आते हैं। यह आपके टेस्ट्स में parallelize जोड़ने जितना आसान है:
इस कॉन्फ़िगरेशन का उपयोग करके, रेल्स आपकी मशीन में प्रोसेसर की संख्या के आधार पर वर्कर प्रोसेस को ऑटोमैटिकली स्पॉन करेगा। रेल्स आपके टेस्ट्स को चलाने के लिए नेमस्पेस्ड डेटाबेस (जैसे database-test-0, database-test-1, आदि) भी बनाएगा।
शुरू करने के लिए बस इतना ही लगता है! बेशक, यदि आपको उनकी आवश्यकता है तो कुछ अतिरिक्त कॉन्फ़िगरेशन विकल्प हैं।
कभी-कभी, आपको समानांतर टेस्ट्स के लिए एक विशिष्ट सेटअप या क्लीनअप करना पड़ सकता है। रेल्स आपके लिए दो हुक प्रदान करता है - parallelize_setup और parallelize_teardown। ये नए वर्कर प्रोसेस स्पॉन होने से पहले और बाद में कॉल किए जाते हैं:
आप वर्कर्स की संख्या को मैन्युअल रूप से भी सेट कर सकते हैं:
वैकल्पिक रूप से, मौजूदा कॉन्फ़िगरेशन को ओवरराइड करने के लिए PARALLEL_WORKERS पर्यावरण चर का उपयोग करें:
थ्रेड्स का उपयोग करके अपने टेस्ट सूट को समानांतर करने का विकल्प भी है।
with: :threads JRuby या TruffleRuby का उपयोग करते समय डिफ़ॉल्ट विकल्प है। थ्रेड्स का उपयोग करना, सिद्धांत रूप में, थोड़ा बेहतर प्रदर्शन प्रदान करता है। आखिरकार, थ्रेड्स को प्रोसेस की तुलना में कम ओवरहेड की आवश्यकता होती है। व्यवहार में, हालांकि, मैंने थ्रेड्स का उपयोग कभी भी बहुत उपयोगी नहीं पाया, और आपको अधिकांश भाग के लिए प्रोसेस-आधारित समानांतरकरण पर ही टिके रहना चाहिए।
नुकसान से सावधान रहें
तो क्या आपको अपने मौजूदा टेस्ट्स में parallelize जोड़कर अविश्वसनीय स्पीडअप का अनुभव करने के लिए बस इतना ही करना है? यह इतना आसान है!
यदि आप भाग्यशाली हैं, तो यह वास्तव में सच है। यह अधिक संभावना है कि जब आप पहली बार अपने मौजूदा टेस्ट सूट में समानांतरकरण जोड़ेंगे तो आप कुछ अप्रत्याशित अड़चनों का सामना करेंगे। यह निश्चित रूप से मेरे लिए मामला था!
एक बात को रास्ते से हटा दें। यदि आप Minitest के बजाय RSpec का उपयोग करते हैं, तो आप भाग्य से बाहर हैं। RSpec रेल्स 6 बिल्ट-इन समानांतर टेस्टिंग को सपोर्ट नहीं करता। इसे बदलने के बारे में चर्चा चल रही है, लेकिन कुछ समय के लिए कोई महत्वपूर्ण प्रगति नहीं हुई है। यदि आप RSpec के साथ समानांतर टेस्ट चाहते हैं, तो आपका सबसे अच्छा विकल्प अभी भी grosser/parallel_tests जैसे थर्ड-पार्टी जेम्स का उपयोग करना है।
एक और अप्रत्याशित मुद्दा जिसका आप सामना कर सकते हैं वह यह है कि समानांतर में टेस्ट्स की एक छोटी संख्या चलाना उन्हें सीरियली चलाने से धीमा कर देता है। समानांतर टेस्ट सेट अप करना एक महत्वपूर्ण ओवरहेड के साथ आता है - जैसे कई डेटाबेस बनाना - जो समानांतरकरण से आपको मिलने वाले किसी भी लाभ को समाप्त कर सकता है।
आप टेस्ट्स की एक छोटी संख्या के लिए समानांतर टेस्ट्स को अक्षम करके बेहतर हो सकते हैं। आप PARALLEL_WORKERS पर्यावरण चर का उपयोग करके ऐसा कर सकते हैं:
रेल्स 7 ने इसे संबोधित किया जब आप कई टेस्ट्स निष्पादित करते हैं तभी समानांतर निष्पादन सक्षम करके। इसलिए यदि आप पहले ही अपग्रेड कर चुके हैं, तो आप इस समस्या का अनुभव नहीं करेंगे। डिफ़ॉल्ट रूप से, समानांतरकरण थ्रेशोल्ड 50 पर सेट है, लेकिन आप इसे ओवरराइड कर सकते हैं:
आखिरी समस्या जिसे मैं हाइलाइट करना चाहता हूं वह वह है जिसका आप सबसे अधिक सामना करने की संभावना रखते हैं, और यह सबसे कपटी और निपटने में सबसे कठिन भी है। जब आप अपने टेस्ट सूट के लिए समानांतर टेस्ट सक्षम करते हैं तो आप रैंडम विफलताएं देखना शुरू कर सकते हैं। यह समझने के लिए कि समानांतरकरण इसका कारण कैसे बन सकता है, आइए एक साधारण टेस्ट केस देखें:
थोड़ा बेकार होने के अलावा, यह टेस्ट पूरी तरह से ठीक है। यह 100% समय पास होगा जब तक यह सीरियली चलाया जाता है। प्रत्येक टेस्ट आइसोलेटेड है, और इन टेस्ट्स को रैंडम ऑर्डर में निष्पादित करने से वे विफल नहीं होते। यह बदल जाता है जब आप मिश्रण में कई प्रोसेस या थ्रेड्स जोड़ते हैं।
जब टेस्ट्स को समानांतर में चलाया जाता है, तो आपके टेस्ट्स में व्यक्तिगत स्टेटमेंट्स का निष्पादन क्रम CPU शेड्यूलिंग के कारण बदल सकता है। उदाहरण को देखते हुए, आप कभी-कभी इस तरह के निष्पादन क्रम देखेंगे:
चूंकि वर्कर 2 ने वर्कर 1 के दावे के निष्पादित होने से पहले फाइल को डिलीट कर दिया, पहला टेस्ट विफल हो जाएगा - कभी-कभी। अपमान में जोड़ने के लिए, एक अलग निष्पादन क्रम कभी-कभी दूसरे टेस्ट को विफल कर देगा और पहले को पास कर देगा।
यह सरल उदाहरण एक मुद्दे को दर्शाता है जो न केवल फाइलों तक बल्कि किसी भी सिंगलटन संसाधन तक फैला हुआ है जिसे आपके टेस्ट नॉन-थ्रेड-सेफ तरीके से एक्सेस करते हैं। मान लीजिए आप रेडिस डेटाबेस या इलास्टिकसर्च इंडेक्स में लिखते हैं। उस मामले में, आप समान जटिलताओं का अनुभव करेंगे। क्या बुरा है, सभी टेस्ट्स को उजागर करने में आपको कुछ समय लग सकता है जो रैंडम विफलताओं का कारण बनते हैं - और उन सभी को ठीक करने में और भी अधिक समय।
फ्लेकी समानांतर टेस्ट्स को संबोधित करने के लिए कोई सिल्वर बुलेट नहीं है। सामान्य तौर पर, आपको यह सुनिश्चित करना होगा कि कई टेस्ट प्रोसेस संसाधनों को साझा न करें। फाइलों के लिए, Tempfiles का उपयोग करें। नेमस्पेस्ड संसाधन (जैसे रेडिस डेटाबेस) बनाने के लिए parallelize_setup का उपयोग करें। और इसी तरह।
मौजूदा रेल्स टेस्ट्स में समानांतर टेस्टिंग जोड़ना
मान लीजिए आप समानांतरकरण के कारण रैंडम टेस्ट विफलताओं से जूझ रहे हैं और उन्हें ठीक करने का समय नहीं है। हालांकि, आप अभी भी समानांतर टेस्टिंग के लाभ प्राप्त करना चाहते हैं। आप इसे केवल अपने टेस्ट्स के एक सबसेट के लिए सक्षम करना पसंद कर सकते हैं।
आखिरकार, केवल वे टेस्ट जो parallelize कॉल करते हैं, समानांतर होंगे, और कंसर्न या पैरेंट क्लासेस का उपयोग करके, आप अपने टेस्ट सूट में एक टेस्ट क्लास के बाद एक समानांतर टेस्टिंग जोड़ सकते हैं। आप इस तरह एक मॉड्यूल बना सकते हैं:
इस मॉड्यूल को शामिल करने वाली कोई भी टेस्ट क्लास अब समानांतर में चलेगी:
वैकल्पिक रूप से, आप ParallelTest जैसी एक नई टेस्ट क्लास बना सकते हैं:
फिर, उन टेस्ट्स के लिए इससे विरासत लें जो समानांतर में चलना चाहिए - और उनको छोड़ दें जो समस्याग्रस्त साबित होते हैं।
समानांतर टेस्टिंग एक बैंड-एड के रूप में
समानांतर टेस्टिंग थोड़े प्रयास के लिए प्रभावशाली गति लाभ प्रदान करती है। मूर्ख मत बनो, हालांकि: यह आपके टेस्ट सूट की गति में सुधार के अन्य दृष्टिकोणों का विकल्प नहीं है, बल्कि एक जोड़ है।
यदि आप पाते हैं कि आपका टेस्ट सूट धीमा है और प्रयास खर्च कर सकते हैं, तो कुछ समय इसे प्रोफाइल करने और धीमेपन के मूल कारण/कारणों को संबोधित करने में बिताएं। समानांतर टेस्टिंग के साथ एक धीमा टेस्ट सूट तेज़ हो जाएगा, लेकिन कभी भी उतना तेज़ नहीं जितना एक पहले से तेज़ टेस्ट सूट जो समानांतर में भी चलता है!
समापन
इस पोस्ट में, हमने देखा कि समानांतर टेस्टिंग क्या है, आप इसे कैसे सेट अप कर सकते हैं और इसे कैसे कॉन्फ़िगर कर सकते हैं। यदि आपको अपने टेस्ट्स को तेज़ करने का कोई तरीका चाहिए, तो समानांतर टेस्टिंग वही प्रदान करती है।
जब आप अपने टेस्ट सूट में समानांतर टेस्टिंग जोड़ते हैं तो आप कुछ बाधाओं का सामना कर सकते हैं। आश्चर्यचकित न हों जब टेस्ट्स जो वर्षों से स्थिर चल रहे थे अचानक विफल होने लगें। आप अपने टेस्ट सूट के केवल एक सबसेट को समानांतर करके उनके चारों ओर काम कर सकते हैं।
कोई फर्क नहीं पड़ता कि आप कौन सा दृष्टिकोण चुनते हैं, समानांतर टेस्टिंग आपके टेस्ट्स को तेज़ करने के लिए एक शानदार टूल है!
हैप्पी कोडिंग!
P.S. यदि आप रूबी मैजिक पोस्ट्स को प्रेस से निकलते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूजलेटर को सब्सक्राइब करें और कभी भी एक भी पोस्ट मिस न करें!
हैंस-जॉर्ग श्नेडलिट्ज़
हमारे गेस्ट ऑथर हैंस वियना, ऑस्ट्रिया के एक रेल्स इंजीनियर हैं। वह अपना अधिकांश समय कोडिंग या कोडिंग के बारे में पढ़ने में बिताते हैं, और कभी-कभी अपने ब्लॉग पर इसके बारे में भी लिखते हैं! जब वह स्क्रीन के सामने नहीं बैठे होते, तो आप शायद उन्हें बाहर, किसी पहाड़ पर चढ़ते हुए पाएंगे।
हैंस-जॉर्ग श्नेडलिट्ज़ के सभी लेख