Raw API के साथ k6 Load Tests में कैप्चा कैसे हल करें

k6 captcha - How to Solve CAPTCHA in k6 Load Tests With the Raw API

k6 में कैप्चा वाला step raw HTTP API से होकर ही गुज़रना पड़ता है, क्योंकि k6 Node नहीं है और उसमें SDK इंस्टॉल नहीं किया जा सकता। यह हिस्सा आसान है: दो calls, submit और poll। जो हिस्सा तय करता है कि आपका test किसी काम का है या नहीं, वह है solve कहां चलता है। इसे default function में रखें तो हर virtual user हर iteration पर solve करता है, जो आपके application के बजाय सॉल्वर को मापता है और ऐसी मशीन पर बोझ डाल देता है जो इसके लिए बनी ही नहीं थी। इसे setup stage में रखें तो आपको साफ़ numbers मिलते हैं, साथ में एक ईमानदार सीमा जो आपको पता होनी चाहिए।

आपको क्या चाहिए

  • k6, कोई भी हाल का version। कोई package इंस्टॉल नहीं करना, क्योंकि इंस्टॉल करने के लिए कुछ है ही नहीं।
  • आप जिस protected endpoint को टेस्ट कर रहे हैं, उसका sitekey और page URL।
  • अगर k6 सॉल्वर वाली ही मशीन पर चलता है तो CapSkip को Local mode में चलाएं, और अगर वह किसी load generator पर या CI में चलता है तो Server mode में। दोनों के बारे में यहां बताया गया है: कनेक्शन सेटिंग्स.

जब solve करना ही सही फ़ैसला है

कोई भी code लिखने से पहले यह साफ़ कह दें। अगर टेस्ट किया जा रहा site आपकी अपनी है, तो अक्सर बेहतर चाल यह है कि load generator को challenge से आगे निकल जाने दें: उसका address allowlist करें, या ऐसा header भेजें जिसे आपका staging environment पहचानता हो, और widget को पूरी तरह छोड़ दें। आप अपने application को मापने की कोशिश कर रहे हैं, और हर हल किया गया challenge ऐसी latency जोड़ता है जो किसी और की है।

solve करना दो मामलों में सही फ़ैसला है। जिस endpoint को हिट करना है वह protected है और उस protection पर आपका नियंत्रण नहीं है, या protected path खुद ही वह चीज़ है जिसे टेस्ट किया जा रहा है, और उसे छोड़ देने का मतलब है ऐसा route टेस्ट करना जिस पर असली traffic कभी नहीं जाता। दोनों असली हैं, और यही पोस्ट का बाकी हिस्सा इन्हीं के लिए है।

यहां SDK काम क्यों नहीं करता

k6 scripts JavaScript जैसी दिखती हैं लेकिन Node पर नहीं चलतीं। require का implementation k6 का अपना है, और documentation इस सीमा के बारे में साफ़-साफ़ कहती है: यह built-in k6 modules, local files और remote scripts लोड करता है, और Node के module resolution algorithm को सपोर्ट नहीं करता। न npm, न node_modules, न fs और न crypto। इसलिए CapSkip package import नहीं किया जा सकता, और न ही कुछ और जिसे आप इस्तेमाल करना चाहें।

यह सुनने में जितना लगता है, उससे कम कीमत में हो जाता है। API 2captcha के साथ compatible है और इसके सिर्फ़ दो endpoints हैं, तो k6 का अपना http module इसे लगभग पंद्रह लाइनों में कवर कर लेता है। अगर आपका load generator आख़िरकार एक सादा Node process निकलता है, तो Node.js कैप्चा सॉल्वर पेज वह उस client को कवर करता है जिसके पास SDK है।

Step 1: solve को एक सादे function के तौर पर लिखें

in.php को submit करें, एक ID पाएं, फिर res.php को तब तक poll करें जब तक जवाब न आ जाए। JSON मांगें ताकि आप pipe character पर strings तोड़ने के बजाय fields पढ़ रहे हों।

// No install step. Both modules are built into k6.
import http from 'k6/http';
import { sleep } from 'k6';

const SOLVER = 'http://127.0.0.1:8080';
const KEY = 'YOUR_API_KEY';

function solve(sitekey, pageurl) {
  const submitted = http.post(SOLVER + '/in.php', {
    key: KEY,
    method: 'userrecaptcha',
    googlekey: sitekey,
    pageurl: pageurl,
    json: '1',
  });

  return poll(submitted.json('request'));   // the captcha ID
}

parameter का नाम ध्यान से देखें। reCAPTCHA को googlekey चाहिए, जबकि Turnstile को turnstile method के साथ sitekey चाहिए। ग़लत वाला भेजना ही आम तौर पर ERROR_GOOGLEKEY response की वजह होता है।

function poll(id) {
  const url = SOLVER + '/res.php?key=' + KEY +
              '&action=get&json=1&id=' + id;

  // Roughly three minutes of headroom at five seconds a try.
  for (let i = 0; i < 36; i++) {
    sleep(5);
    const res = http.get(url);
    if (res.json('status') === 1) {
      return res.json('request');   // the token
    }
  }
  throw new Error('solve did not finish in time');
}

अभी बाकी जवाब CAPCHA_NOT_READY के रूप में status zero के साथ वापस आता है, यही वजह है कि loop status field जांचता है, न कि किसी भी response को पूरा मान लेता है। नतीजे सिर्फ़ एक बार पढ़े जा सकते हैं, इसलिए token मिलते ही उसे संभाल कर रखें।

Step 2: setup stage में solve करें

k6 setup को एक बार चलाता है, किसी भी virtual user के शुरू होने से पहले, और यह जो भी लौटाता है उसे default function में पास कर देता है। यही वह ढांचा है जिसकी ज़रूरत है। वहीं solve करें, tokens बांट दें, और कोई भी VU अपनी iteration के अंदर solve की कीमत नहीं चुकाता।

const PAGE = 'https://example.com/page-with-recaptcha';
const SITEKEY = 'YOUR_SITEKEY';

export const options = {
  vus: 10,
  duration: '90s',
  setupTimeout: '5m',   // the 60s default expires mid solve
};

export function setup() {
  // One token per VU. They are single use.
  const tokens = [];
  for (let i = 0; i < 10; i++) {
    tokens.push(solve(SITEKEY, PAGE));
  }
  return { tokens };
}

setupTimeout वाली लाइन दिखने से कहीं ज़्यादा मायने रखती है। k6 डिफ़ॉल्ट रूप से setup को 60 seconds देता है, और एक अकेला reCAPTCHA solve अपने आप में उसका ज़्यादातर हिस्सा खा सकता है। ऐसे दस solves उसमें नहीं समाएंगे, stage मार दिया जाता है, और error setup को दोष देता है, न कि उस चीज़ को जिसे आप देखने की सोचते।

इस पर आगे कुछ बनाने से पहले जानने लायक़ एक सीमा

Tokens सिर्फ़ एक बार इस्तेमाल होते हैं और लगभग दो मिनट तक वैध रहते हैं। यहां दोनों बातें असर डालती हैं। सिर्फ़ एक बार इस्तेमाल का मतलब है कि आपको कम से कम उतने ही tokens चाहिए जितने protected requests, तो जो test guarded endpoint को एक हज़ार बार हिट करता है उसे एक हज़ार solves चाहिए, और वह अब load test जैसा नहीं रह जाता। दो मिनट का मतलब है कि setup में हल किए गए tokens पहले VU के शुरू होते ही बूढ़े होने लगते हैं, तो कोई लंबा soak test अपना ज़्यादातर समय expired tokens submit करने में बिताएगा।

तो यह pattern किसी protected endpoint के खिलाफ़ एक छोटे burst के लिए ठीक बैठता है, तीस minute के soak के लिए नहीं। reCAPTCHA token कितनी देर वैध रहता है, इस पर लिखी पोस्ट में timings मौजूद हैं। अगर आपको widget के ज़रिए लगातार load चाहिए, तो पहले बताया गया allowlist रास्ता ही इसे पाने का इकलौता ईमानदार तरीक़ा है।

Step 3: सॉल्वर को अपने metrics से बाहर रखें

k6 के अपने http module से जो कुछ भी आप भेजते हैं वह http_req_duration में आ जाता है, सॉल्वर calls भी शामिल। ऐसा p95 जो चुपचाप एक पंद्रह second के poll को शामिल कर लेता है, ऐसा नंबर नहीं है जिस पर आप कुछ कर सकें। जिन requests की आपको परवाह है उन्हें tag करें और thresholds को उस tag पर लगाएं।

export const options = {
  vus: 10,
  duration: '90s',
  setupTimeout: '5m',
  thresholds: {
    // Measure the app, not the solve.
    'http_req_duration{target:app}': ['p(95)<500'],
  },
};

export default function (data) {
  const token = data.tokens[__VU - 1];

  http.post(PAGE, { 'g-recaptcha-response': token }, {
    tags: { target: 'app' },
  });
}

__VU variable virtual users को एक से गिनता है, तो token array को इससे index करने पर हर VU को अपना token मिल जाता है। solve को कहीं ऐसी जगह ले जाने से जहां k6 न देख सके, tagging ज़्यादा साफ़ हल है, क्योंकि solve requests फिर भी output में दिखती हैं जब आपको जानना हो कि उनमें कितना समय लगा।

सॉल्वर को कहाँ रहना चाहिए

Load generators शायद ही कभी आपका डेस्कटॉप होते हैं। k6 CI में, किसी dedicated box पर, या किसी managed service पर चलता है, और इनमें से किसी पर भी loopback address उस मशीन का नहीं है जिस पर आपका सॉल्वर है।

मोडकिस पर सुनता हैकब इस्तेमाल करें
लोकल127.0.0.1, केवल उसी डिवाइस परk6 और सॉल्वर एक ही मशीन पर
सर्वरआपका नेटवर्क पता या पब्लिक IPCI, एक load generator fleet, एक managed runner

दूसरी row की हर चीज़ के लिए जवाब Server mode है: app में listen address बदलें, script को उस host पर लगाएं, और हर generator एक ही सॉल्वर साझा करती है। जब callers आपके network से बाहर बैठे हों तो एक static public IP की सलाह दी जाती है। यह अब भी आपका hardware है और अब भी unmetered है, तो इससे बस यह बदलता है कि सॉल्वर कहां चलता है, और कुछ नहीं। CapSkip एक Windows application है, तो यह एक ही Windows box होता है जिसे generators कॉल करते हैं। एक व्यावहारिक बात: इसे उसी load balancer के पीछे न रखें जिसे आप टेस्ट कर रहे हैं, वरना आप अपनी ही bottleneck को दो बार मापेंगे।

आम errors

आप जो देखते हैंकारणफिक्स
module 'capskip' नहीं मिलाk6 npm packages resolve नहीं करताइसके बजाय k6 के अपने http module से API को call करें
setup() execution timeout हो गयाsolves 60 second के डिफ़ॉल्ट से ज़्यादा समय ले गएहर solve को कवर करने के लिए setupTimeout बढ़ाएं
p95 बहुत बड़ा है और कुछ भी धीमा नहीं हैसॉल्वर calls http_req_duration में गिन ली गईंapp requests को tag करें और threshold को filter करें
बाद की iterations अस्वीकार, शुरुआती ठीकTokens अपनी lifetime से ज़्यादा पुराने हो गएrun को छोटा करें या कम solve करें, बाद में
हर VU को एक जैसा rejection मिलता हैएक ही token कई VUs में दोबारा इस्तेमाल हुआहर VU के लिए एक solve करें और __VU से index करें

हर code की पूरी सूची और हर method जो parameters लेता है, वह यहां दिया गया है: CapSkip API डॉक्यूमेंटेशन.

FAQ

क्या मैं CapSkip SDK को k6 में इंस्टॉल कर सकता हूं?

नहीं। k6 अपना ख़ुद का module loader इस्तेमाल करता है जो built-in modules, local files और remote scripts संभालता है, और जानबूझकर Node के resolution algorithm को फॉलो नहीं करता, तो npm packages इसमें शामिल नहीं हैं। API 2captcha के साथ compatible है, तो वे दो endpoints वही सब कवर कर लेते हैं जो SDK आपके लिए करता, k6 के अपने http module की लगभग पंद्रह लाइनों में।

क्या मुझे इसके बजाय default function के अंदर solve करना चाहिए?

सिर्फ़ तभी जब solve खुद वह चीज़ हो जिसे आप टेस्ट कर रहे हैं। default function हर VU की हर iteration पर एक बार चलता है, तो दो minute तक बीस VUs का मतलब है सैकड़ों solves, और आपके latency numbers polling की माप बन जाते हैं। setup में solve करें, tokens बांट दें, और iteration को उसी request तक सीमित रखें जिसकी असल में परवाह है।

मेरा k6 किसी managed service पर चलता है। क्या यह सॉल्वर तक पहुंच सकता है?

हां, Server mode में। सॉल्वर loopback address की जगह एक network address पर सुनता है, और generators इसे API के ज़रिए किसी और internal service की तरह call करते हैं। जब runners आपके network से बाहर बैठे हों तो एक static public IP इसे स्थिर बनाती है। key validation चालू करें और हर environment को उसकी अपनी key दें ताकि एक को दूसरों को छुए बिना revoke किया जा सके।

मैं किसी widget के ज़रिए एक घंटे तक load test कैसे करूं?

आप नहीं करते, कम से कम असली tokens के ज़रिए नहीं। सिर्फ़ एक बार इस्तेमाल और दो minute की lifetime का मतलब है कि एक घंटे के लगातार load के लिए solves की एक निरंतर धारा चाहिए, और उस बिंदु पर सॉल्वर ही वह system बन जाता है जिसे टेस्ट किया जा रहा है। अपने application पर लंबे run के लिए, load generator को challenge से छूट दें और उसके पीछे वाले path को टेस्ट करें।

संक्षेप में

in.php और res.php के खिलाफ़ k6 के अपने http module का इस्तेमाल करें, setupTimeout बढ़ाकर setup में solve करें, अपने application requests को tag करें ताकि thresholds मतलब की बनी रहें, और run को इतना छोटा रखें कि tokens अभी भी ज़िंदा हों। इसके crawl वाले पहलू के लिए देखें वेब स्क्रैपिंग के लिए कैप्चा सॉल्वर पेज. Load testing वह जगह है जहां per solve pricing सबसे तेज़ी से बेतुकी हो जाती है, क्योंकि एक ही burst को सैकड़ों tokens चाहिए हो सकते हैं जो बिल्कुल कोई business value पैदा नहीं करते। pricing model ही पूरा फ़र्क़ है: कैप्चा बायपास ऐसे हार्डवेयर पर चलना जो पहले से आपका अपना है, एक जैसी कीमत रखता है चाहे आप एक test चलाएं या चालीस।