डॉक्यूमेंटेशन और टेस्ट केस: OpenResty डेवलपमेंट समस्याओं को हल करने के शक्तिशाली उपकरण
API7.ai
October 23, 2022
OpenResty के सिद्धांतों और कुछ आवश्यक अवधारणाओं को सीखने के बाद, हम अंततः API सीखना शुरू करने जा रहे हैं।
मेरे व्यक्तिगत अनुभव से, OpenResty API सीखना अपेक्षाकृत आसान है, इसलिए इसे समझाने के लिए कई लेखों की आवश्यकता नहीं है। आप सोच रहे होंगे: क्या API सबसे सामान्य और आवश्यक हिस्सा नहीं है? इस पर बहुत समय क्यों नहीं लगाया जाता? इसके पीछे दो प्राथमिक विचार हैं।
पहला, OpenResty बहुत विस्तृत दस्तावेज़ीकरण प्रदान करता है। कई अन्य प्रोग्रामिंग भाषाओं या प्लेटफॉर्म्स की तुलना में, OpenResty न केवल API पैरामीटर्स और रिटर्न वैल्यू परिभाषाएं प्रदान करता है, बल्कि पूर्ण और चलाने योग्य कोड उदाहरण भी प्रदान करता है, जो स्पष्ट रूप से दिखाता है कि API विभिन्न सीमा स्थितियों को कैसे संभालता है।
उदाहरण कोड और चेतावनियों के साथ API परिभाषा का पालन करना OpenResty दस्तावेज़ीकरण का एक सुसंगत शैली है। इसलिए, API विवरण पढ़ने के बाद, आप तुरंत नमूना कोड को अपने वातावरण में चला सकते हैं और पैरामीटर्स और दस्तावेज़ीकरण को संशोधित करके उन्हें सत्यापित कर सकते हैं और अपनी समझ को गहरा कर सकते हैं।
दूसरा, OpenResty व्यापक टेस्ट केस प्रदान करता है। जैसा कि मैंने उल्लेख किया, OpenResty दस्तावेज़ीकरण API के कोड उदाहरण दिखाता है। हालांकि, स्थान की सीमाओं के कारण, दस्तावेज़ विभिन्न असामान्य स्थितियों में त्रुटि रिपोर्टिंग और प्रसंस्करण और कई API का उपयोग करने की विधि प्रस्तुत नहीं करता है।
लेकिन चिंता न करें। आप इनमें से अधिकांश सामग्री टेस्ट केस सेट में पा सकते हैं।
OpenResty डेवलपर्स के लिए, सर्वोत्तम API सीखने की सामग्री आधिकारिक दस्तावेज़ीकरण और टेस्ट केस हैं, जो पेशेवर और पाठकों के लिए अनुकूल हैं।
एक व्यक्ति को मछली दो, और तुम उसे एक दिन के लिए खिलाओगे; एक व्यक्ति को मछली पकड़ना सिखाओ, और तुम उसे जीवन भर के लिए खिलाओगे। आइए एक वास्तविक उदाहरण का उपयोग करके अनुभव करें कि OpenResty विकास में दस्तावेज़ीकरण और टेस्ट केस सेट की शक्ति का उपयोग कैसे करें।
shdict के get API को उदाहरण के रूप में लें
NGINX साझा मेमोरी क्षेत्र पर आधारित, साझा डिक्शनरी (shared dictionary) एक Lua डिक्शनरी ऑब्जेक्ट है, जो कई वर्कर्स के बीच डेटा एक्सेस कर सकता है और रेट लिमिटिंग, कैश आदि जैसे डेटा को स्टोर कर सकता है। साझा डिक्शनरी से संबंधित 20 से अधिक API हैं - OpenResty में सबसे अधिक उपयोग किए जाने वाले और महत्वपूर्ण API।
आइए सबसे सरल get ऑपरेशन को उदाहरण के रूप में लें; आप दस्तावेज़ीकरण लिंक पर क्लिक करके तुलना कर सकते हैं। निम्नलिखित न्यूनतम कोड उदाहरण आधिकारिक दस्तावेज़ीकरण से अनुकूलित किया गया है।
http { lua_shared_dict dogs 10m; server { location /demo { content_by_lua_block { local dogs = ngx.shared.dogs dogs:set("Jim", 8) local v = dogs:get("Jim") ngx.say(v) } } } }
एक त्वरित नोट के रूप में, Lua कोड में साझा डिक्शनरी का उपयोग करने से पहले, हमें nginx.conf में lua_shared_dict निर्देश के साथ मेमोरी का एक ब्लॉक जोड़ना होगा, जिसका नाम "dogs" है और आकार 10M है। nginx.conf को संशोधित करने के बाद, आपको प्रक्रिया को पुनः आरंभ करना होगा और परिणाम देखने के लिए ब्राउज़र या curl कमांड का उपयोग करना होगा।
क्या यह थोड़ा थकाऊ नहीं लगता? आइए इसे और सरल तरीके से संशोधित करें। जैसा कि आप देख सकते हैं, इस तरह से resty CLI का उपयोग करना nginx.conf में कोड को एम्बेड करने के समान प्रभाव देता है।
$ resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs dogs:set("Jim", 8) local v = dogs:get("Jim") ngx.say(v) '
अब आप जानते हैं कि nginx.conf और Lua कोड कैसे एक साथ काम करते हैं, और आपने साझा डिक्शनरी के set और get मेथड को सफलतापूर्वक चलाया है। आमतौर पर, अधिकांश डेवलपर्स यहीं रुक जाते हैं। यहां कुछ बातें ध्यान देने योग्य हैं।
- कौन से चरण साझा मेमोरी से संबंधित API का उपयोग नहीं कर सकते?
- हम नमूना कोड में देखते हैं कि get फ़ंक्शन में केवल एक रिटर्न वैल्यू है। तो कब एक से अधिक रिटर्न वैल्यू होगा?
- get फ़ंक्शन का इनपुट किस प्रकार का है? क्या लंबाई सीमा है?
इन प्रश्नों को कम न समझें; ये हमें OpenResty को बेहतर ढंग से समझने में मदद कर सकते हैं, और मैं आपको इन्हें एक-एक करके समझाऊंगा।
प्रश्न 1: कौन से चरण साझा मेमोरी से संबंधित API का उपयोग नहीं कर सकते?
आइए पहले प्रश्न को देखें। उत्तर सरल है; दस्तावेज़ीकरण में एक समर्पित context (यानी संदर्भ अनुभाग) है जो उन वातावरणों को सूचीबद्ध करता है जिनमें API का उपयोग किया जा सकता है।
context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*
जैसा कि आप देख सकते हैं, init और init_worker चरण शामिल नहीं हैं, जिसका अर्थ है कि साझा मेमोरी का get API इन दो चरणों में उपयोग नहीं किया जा सकता। कृपया ध्यान दें कि प्रत्येक साझा मेमोरी API विभिन्न चरणों में उपयोग किया जा सकता है। उदाहरण के लिए, set API का उपयोग init चरण में किया जा सकता है।
हमेशा, उपयोग करते समय दस्तावेज़ीकरण पढ़ें। बेशक, OpenResty का दस्तावेज़ीकरण कभी-कभी त्रुटियों और चूक से भरा होता है, इसलिए आपको उन्हें वास्तविक परीक्षणों के साथ सत्यापित करने की आवश्यकता है।
अगला, आइए टेस्ट सेट को संशोधित करें यह सुनिश्चित करने के लिए कि init चरण साझा डिक्शनरी का get API चला सकता है
साझा मेमोरी से संबंधित टेस्ट केस सेट कैसे ढूंढें? OpenResty के टेस्ट केस सभी /t डायरेक्टरी में रखे गए हैं और नियमित रूप से नामित हैं, यानी self-incremented-number-function-name.t। shdict के लिए खोजें, और आपको 043-shdict.t मिलेगा, साझा मेमोरी टेस्ट केस सेट, जिसमें विभिन्न सामान्य और असामान्य परिस्थितियों के लिए लगभग 100 टेस्ट केस शामिल हैं।
आइए पहले टेस्ट केस को संशोधित करने का प्रयास करें।
आप content चरण को init चरण से बदल सकते हैं और अतिरिक्त कोड को हटा सकते हैं यह देखने के लिए कि get इंटरफ़ेस काम करता है या नहीं। इस चरण में आपको यह समझने की आवश्यकता नहीं है कि टेस्ट केस कैसे लिखा, संगठित और चलाया जाता है। आपको केवल यह जानना है कि यह get इंटरफ़ेस का परीक्षण कर रहा है।
=== TEST 1: string key, int value --- http_config lua_shared_dict dogs 1m; --- config location = /test { init_by_lua ' local dogs = ngx.shared.dogs local val = dogs:get("foo") ngx.say(val) '; } --- request GET /test --- response_body 32 --- no_error_log [error] --- ONLY
आपने ध्यान दिया होगा कि टेस्ट केस के अंत में, मैंने --ONLY फ्लैग जोड़ा है, जिसका अर्थ है कि अन्य सभी टेस्ट केस को अनदेखा करें, और केवल इस एक को चलाएं, इस प्रकार चलाने की गति में सुधार करें। बाद में टेस्ट अनुभाग में, मैं विभिन्न टैग्स को विशेष रूप से समझाऊंगा।
संशोधन के बाद, हम prove कमांड के साथ टेस्ट केस चला सकते हैं।
prove t/043-shdict.t
फिर, आपको एक त्रुटि मिलेगी जो दस्तावेज़ीकरण में वर्णित चरण सीमाओं की पुष्टि करती है।
nginx: [emerg] "init_by_lua" directive is not allowed here
प्रश्न 2: get फ़ंक्शन में कब एक से अधिक रिटर्न वैल्यू होगा?
आइए दूसरे प्रश्न को देखें, जिसे आधिकारिक दस्तावेज़ीकरण से संक्षेप में प्रस्तुत किया जा सकता है। दस्तावेज़ीकरण इस इंटरफ़ेस की syntax विवरण से शुरू होता है।
value, flags = ngx.shared.DICT:get(key)
सामान्य परिस्थितियों में।
- पहला पैरामीटर
valueडिक्शनरी मेंkeyके अनुरूप मान लौटाता है; हालांकि, जबkeyमौजूद नहीं होता या समाप्त हो जाता है, तोvalueमानnilहोता है। - दूसरा पैरामीटर,
flags, थोड़ा अधिक जटिल है; यदि set इंटरफ़ेस ने flags सेट किए हैं, तो यह उन्हें लौटाता है। अन्यथा, यह नहीं करता है।
यदि API कॉल गलत हो जाती है, तो value nil लौटाता है, और flags एक विशिष्ट त्रुटि संदेश लौटाता है।
दस्तावेज़ीकरण में संक्षेपित जानकारी से, हम देख सकते हैं कि local v = dogs:get("Jim") केवल एक प्राप्त करने वाले पैरामीटर के साथ लिखा गया है। ऐसा लिखना अधूरा है क्योंकि यह केवल सामान्य उपयोग परिदृश्य को कवर करता है बिना दूसरे पैरामीटर को प्राप्त करने या अपवाद संभालने के। हम इसे निम्नलिखित में संशोधित कर सकते हैं।
local data, err = dogs:get("Jim") if data == nil and err then ngx.say("get not ok: ", err) return end
पहले प्रश्न की तरह, हम दस्तावेज़ीकरण की अपनी समझ की पुष्टि करने के लिए टेस्ट केस सेट में खोज कर सकते हैं।
=== TEST 65: get nil key --- http_config lua_shared_dict dogs 1m; --- config location = /test { content_by_lua ' local dogs = ngx.shared.dogs local ok, err = dogs:get(nil) if not ok then ngx.say("not ok: ", err) return end ngx.say("ok") '; } --- request GET /test --- response_body not ok: nil key --- no_error_log [error]
इस टेस्ट केस में, get इंटरफ़ेस में nil इनपुट है, और लौटाया गया err संदेश nil key है। यह सत्यापित करता है कि दस्तावेज़ीकरण का हमारा विश्लेषण सही है और तीसरे प्रश्न का आंशिक उत्तर प्रदान करता है। कम से कम, get का इनपुट nil नहीं हो सकता।
प्रश्न 3: get फ़ंक्शन का इनपुट किस प्रकार का है?
तीसरे प्रश्न के रूप में, get के इनपुट पैरामीटर्स किस प्रकार के हो सकते हैं? आइए पहले दस्तावेज़ीकरण की जांच करें, लेकिन दुर्भाग्य से, आप पाएंगे कि दस्तावेज़ीकरण यह निर्दिष्ट नहीं करता है कि keys के कानूनी प्रकार क्या हैं। हम क्या करें?
चिंता न करें। कम से कम हम जानते हैं कि key एक स्ट्रिंग प्रकार हो सकता है और nil नहीं हो सकता। क्या आपको Lua में डेटा प्रकार याद हैं? स्ट्रिंग्स और nil के अलावा, संख्याएं, सरणियाँ, बूलियन प्रकार और फ़ंक्शन हैं। बाद के दो को keys के रूप में अनावश्यक हैं, इसलिए हमें केवल पहले दो को सत्यापित करने की आवश्यकता है: संख्याएं और सरणियाँ। हम टेस्ट फ़ाइल में उन मामलों की खोज करके शुरू कर सकते हैं जहां संख्याओं को key के रूप में उपयोग किया जाता है।
=== TEST 4: number keys, string values
इस टेस्ट केस के साथ, आप देख सकते हैं कि संख्याओं को भी keys के रूप में उपयोग किया जा सकता है, और आंतरिक रूप से उन्हें स्ट्रिंग्स में परिवर्तित किया जाएगा। सरणियों के बारे में क्या? दुर्भाग्य से, टेस्ट केस इसे कवर नहीं करता है, इसलिए हमें इसे स्वयं आज़माने की आवश्यकता है।
$ resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs dogs:get({}) '
आश्चर्य की बात नहीं, निम्नलिखित त्रुटि रिपोर्ट की गई।
ERROR: (command line -e):2: bad argument #1 to 'get' (string expected, got table)
संक्षेप में, हम यह निष्कर्ष निकाल सकते हैं कि get API द्वारा स्वीकार किए जाने वाले key प्रकार स्ट्रिंग्स और संख्याएं हैं।
तो क्या इनपुट key की लंबाई की कोई सीमा है? यहां एक संबंधित टेस्ट केस है।
=== TEST 67: get a too-long key --- http_config lua_shared_dict dogs 1m; --- config location = /test { content_by_lua ' local dogs = ngx.shared.dogs local ok, err = dogs:get(string.rep("a", 65536)) if not ok then ngx.say("not ok: ", err) return end ngx.say("ok") '; } --- request GET /test --- response_body not ok: key too long --- no_error_log [error]
जब स्ट्रिंग की लंबाई 65536 होती है, तो आपको key बहुत लंबी होने का संकेत मिलेगा। आप लंबाई को 65535 में बदलने का प्रयास कर सकते हैं, हालांकि केवल 1 बाइट कम, लेकिन कोई और त्रुटि नहीं। इसका मतलब है कि key की अधिकतम लंबाई ठीक 65535 है।
सारांश
अंत में, मैं आपको याद दिलाना चाहता हूं कि OpenResty API में, किसी भी त्रुटि संदेश के साथ रिटर्न वैल्यू को प्राप्त करने और त्रुटि संभालने के लिए एक वेरिएबल होना चाहिए, अन्यथा गलती होगी। उदाहरण के लिए, यदि गलत कनेक्शन को कनेक्शन पूल में डाल दिया जाता है, या यदि API कॉल विफल हो जाती है तो इसके पीछे के तर्क को जारी रखना, यह लोगों को लगातार शिकायत करने का कारण बनता है।
तो, जब आप OpenResty कोड लिखते हैं और कोई समस्या आती है, तो आप आमतौर पर इसे कैसे हल करते हैं? क्या यह दस्तावेज़ीकरण, मेलिंग सूची, या अन्य चैनल हैं?
कृपया इस लेख को अपने सहयोगियों और दोस्तों के साथ साझा करें ताकि हम संवाद कर सकें और सुधार कर सकें।