uncloth.app गाइड

Image generation को स्केल करना: queues, idempotency और retries

Image generation उन धारणाओं को तोड़ देती है जिन पर ज़्यादातर वेब आर्किटेक्चर टिकी होती हैं। Requests मिलीसेकंड नहीं, दसियों सेकंड लेती हैं; capacity सचमुच सीमित है क्योंकि वह भौतिक है; और एक विफल request पहले ही असली पैसा ख़र्च कर चुकी होती है। इसे सही रखने वाले pattern जाने-पहचाने हैं — बस वे नहीं हैं जो एक सामान्य CRUD backend में पहले से मौजूद होते हैं।

Queue ही डिज़ाइन है

पहली प्रवृत्ति होती है request handler से सीधे API कॉल करना। यह development में चलता है और असली ट्रैफ़िक आते ही पहली बार में फ़ेल हो जाता है, क्योंकि माँग और capacity के बीच कुछ है ही नहीं: एक उछाल timeouts की दीवार बन जाता है, और process के restart होते समय क्या चल रहा था इसका कोई रिकॉर्ड नहीं बचता।

बीच में एक durable queue रखिए। "Durable" यहाँ कुंजी शब्द है — in-memory सूची deploy पर हर चालू job खो देती है, और deploy ट्रैफ़िक के दौरान ही होते हैं। इस पैमाने पर डेटाबेस टेबल बख़ूबी काम करती है और साथ में state का रिकवर करने योग्य रिकॉर्ड भी दे देती है।

Backpressure एक फ़ीचर है

Queue होने पर आप तय कर सकते हैं कि एक साथ कितने jobs चलने दिए जाएँ, और वह सीमा तकनीकी ब्योरा नहीं, प्रोडक्ट का फ़ैसला है। बहुत ऊँची रखी तो सबके लिए सब कुछ धीमा। बहुत नीची रखी तो queue बढ़ती रहेगी और capacity बेकार पड़ी रहेगी। असल बात यह है कि सीमा मौजूद हो और एक ही जगह लागू हो, ताकि ट्रैफ़िक का उछाल हर request को बिगाड़ने के बजाय queue लंबी कर दे।

Idempotency और अस्पष्ट failure

जो failure पैसे ख़र्च कराती है वह error response नहीं है — errors आसान हैं। वह अस्पष्ट स्थिति है: request आपके process से निकल गई, कनेक्शन गिर गया, और आप बता नहीं सकते कि job बना या नहीं। retry किया तो शायद दो बार भुगतान हो गया। न किया तो शायद यूज़र ने पैसे देकर कुछ पाया ही नहीं।

Idempotency key इसे retry को सुरक्षित बनाकर हल करती है: वही key दूसरा job बनाने के बजाय मूल job लौटा देती है। नियम सरल हैं और ग़लत करना आसान — key तब बनाइए जब यूज़र कार्रवाई करता है, तब नहीं जब HTTP कॉल होती है; उसे job रिकॉर्ड के साथ स्टोर कीजिए; उस कार्रवाई के हर retry में उसी को दोबारा इस्तेमाल कीजिए।

# एक यूज़र ऐक्शन के हर retry के लिए वही key
KEY=$(uuidgen)
curl -X POST https://api.example/api/v1/jobs \
  -H "X-API-Key: $API_KEY" -H "Idempotency-Key: $KEY" \
  -F image=@photo.jpg -F feature=undress -F consent=confirmed

किसे अपने आप retry नहीं करना चाहिए

failures की एक श्रेणी ऐसी है जहाँ सुरक्षित क़दम रुक जाना है। अगर submission भेजने और response दर्ज करने के बीच आपका process मर गया, तो आप सचमुच नहीं जानते कि क्या हुआ — और deduplicate करने के लिए key के बिना अपने आप होने वाला retry सिक्का उछालने जैसा है जो दो बार बिल कर सकता है। ऐसे jobs को आँख मूँदकर दोहराने के बजाय "ध्यान चाहिए" के रूप में चिह्नित कीजिए। दिखने वाला अटका हुआ job चुपचाप हुए दोहरे शुल्क से बेहतर नतीजा है।

Reconciliation: वह loop जो आपको बचाता है

लाइव events सुविधाजनक हैं और अविश्वसनीय भी। Sockets गिरते हैं, processes restart होते हैं, और जो एक संदेश मायने रखता था वह तब आता है जब कोई सुन नहीं रहा। इसका समाधान एक बैकग्राउंड loop है जो समय-समय पर API से उन सभी jobs के बारे में पूछता है जिन्हें आपका डेटाबेस अब भी सक्रिय मानता है, और जवाब से state अपडेट कर देता है।

यह अकेला loop बग्स की पूरी श्रेणी सोख लेता है। छूटे हुए events मायने रखना बंद कर देते हैं। जनरेशन के बीच में हुआ restart मायने रखना बंद कर देता है। बीच में कनेक्शन के साथ जो भी हुआ हो, हर job एक reconciliation अंतराल के भीतर अपनी असली स्थिति पर आ जाता है।

डेटाबेस को कूटे बिना प्रोग्रेस दिखाना

जनरेशन बार-बार प्रोग्रेस भेजती है — प्रति job संभवतः सेकंड में कई बार। हर tick डेटाबेस में लिखना बिना किसी अतिरिक्त जानकारी के आपका write load कई गुना कर देता है। Persistence को लगभग एक बार प्रति सेकंड तक सीमित कीजिए और अंतिम state हमेशा लिखिए, फिर लाइव मान जुड़े हुए clients तक storage को छुए बिना broadcast कीजिए।

एक चेकलिस्ट जो टिकती है

  • यूज़र्स और API के बीच durable queue, restart के बाद रिकवर करने योग्य।
  • चालू jobs की स्पष्ट सीमा, एक ही जगह लागू।
  • प्रति यूज़र ऐक्शन बनी, स्टोर की गई और retry पर दोबारा इस्तेमाल होने वाली idempotency key।
  • अस्पष्ट dispatch failures को अपने आप retry करने के बजाय चिह्नित करना।
  • एक reconciliation loop जो छूटे events के बावजूद state को सही जगह ले आए।
  • सीमित दर पर प्रोग्रेस लिखना, लाइव प्रोग्रेस socket पर भेजना।

इसमें कुछ भी image generation के लिए ख़ास नहीं है — यह सामान्य distributed-systems स्वच्छता है। बस यहाँ दिखने लगती है, क्योंकि काम की हर इकाई इतनी धीमी और इतनी महँगी है कि हमेशा वाले शॉर्टकट अदृश्य नहीं रह पाते।

अक्सर पूछे जाने वाले सवाल

क्या मुझे message broker चाहिए?

इस पैमाने पर आम तौर पर नहीं। claim query वाली डेटाबेस टेबल एक और चलते-फिरते हिस्से के बिना ही durability और state का रिकवर करने योग्य रिकॉर्ड दे देती है।

एक साथ कितने jobs चलने देने चाहिए?

कम से शुरू कीजिए, queue के इंतज़ार को completion time के मुक़ाबले नापिए, और तब तक बढ़ाइए जब तक latency सुधरना बंद न कर दे। संख्या से ज़्यादा मायने यह रखता है कि एक लागू सीमा मौजूद हो।

क्या विफल jobs अपने आप retry होने चाहिए?

स्पष्ट errors, हाँ। अस्पष्ट dispatch failures जहाँ आप बता नहीं सकते कि काम बना या नहीं — नहीं; उन्हें चिह्नित कीजिए, क्योंकि आँख मूँदकर किया गया retry भुगतान की गई generation दोहरा सकता है।

uncloth.app पर बनाएँ

एक REST endpoint, ग्यारह presets, नतीजे सीधे आपके backend को। बताइए आप क्या बना रहे हैं, हम access की जानकारी भेज देंगे।

एक्सेस का अनुरोध करें

सभी गाइड