ChatGPT की एक गलती से ₹15 लाख से अधिक का revenue loss
(asim.bearblog.dev)- monetization अभी-अभी चालू करने वाले startup को subscription payment outage का सामना करना पड़ा, लेकिन internally reproduce न हो पाने के कारण 5 दिनों तक root cause की पहचान में देरी हुई
- outage की शुरुआत तब हुई जब ChatGPT द्वारा बनाए गए Prisma/TypeScript→Python/SQLAlchemy conversion format को copy करते समय UUID generation function की जगह hardcoded ID string default value जैसी डाल दी गई
- AWS ECS के 8 tasks और हर task में 5 instances वाली structure के कारण users अधिकतम 40 unique ID pools में से किसी एक से टकराते थे, और दिन में frequent deployments की वजह से समस्या छिपी रही
- रात में deployments रुकने पर हर server की single ID exhaust हो गई, और उसके बाद नई subscription attempts unique ID collision के कारण fail होने लगीं
- रोज़ 50 complaints, 5 दिन, और $40/month subscription fee के आधार पर loss monthly $10,000 अनुमानित है; testing, logging, alerts की कमी और code copy करने से incident response और बड़ा हो गया
monetization के तुरंत बाद सामने आया subscription outage
- startup ने मई में पहली बार monetization चालू किया और launch के 1 घंटे के भीतर पहला customer मिला
- अगली सुबह Gmail में users की 40 से अधिक complaints जमा थीं
- users subscription complete नहीं कर पा रहे थे
- उन्होंने बताया कि subscription button दबाने पर infinite loading spinner दिखता है
- नया account बनाकर खुद verify किया, लेकिन internally subscription सही चल रही थी, इसलिए cause reproduce नहीं हो पाया
- working hours में complaints लगभग नहीं थीं, और outage मुख्य रूप से रातभर जमा होता था
time pressure में monetization implementation
- मई वह समय था जब YC S23 batch शुरू हुआ था, और team launch के बाद best direction को लेकर sure नहीं थी
- YC group partner Dalton ने paid subscribers को direction तय करने का metric बनाने और सोची गई monthly price को double करने की सलाह दी
- final price $40/month तय की गई
- project मूल रूप से full-stack NextJS था, लेकिन monetization work के आसपास Python/FastAPI migration चल रहा था
- migration process में ChatGPT का इस्तेमाल किया गया
- Stripe integration भी complete किया गया
- इसके बाद 5 दिनों तक sleep काफी कम हो गई, और रोज़ 30–50 complaint emails handle करने पड़े
ChatGPT द्वारा बनाया गया model conversion format
- backend migration के दौरान database models को Prisma/TypeScript से Python/SQLAlchemy में move किया गया
- model conversion tedious था और लगा कि ChatGPT इसे अच्छी तरह कर रहा है, इसलिए लगभग पूरी migration में इसका इस्तेमाल किया गया
- generated code को copy-paste करने के बाद behavior verify किया गया, और production में भी यह normal जैसा दिखा, इसलिए आगे बढ़ गए
- उस समय database inserts अभी भी Next API संभाल रहा था, और Python backend केवल database read करता था
- subscription feature implement करते समय पहली बार Python से DB records insert करना शुरू हुआ
- नया SQLAlchemy model खुद बनाया गया, लेकिन existing models से ChatGPT द्वारा बनाया format जस का तस copy किया गया
- सभी models की ID generation method में वही problem आ गई
असली कारण और दिन में क्यों नहीं दिखा
- core bug यह था कि UUID generate करने वाला function या lambda pass करने के बजाय एक single hardcoded ID string pass कर दी गई
- किसी specific backend instance पर एक user उस ID से subscription complete कर लेता, तो उसी instance पर बाद की subscription attempts unique ID collision पैदा करतीं
- backend configuration ने इस problem को और देर तक छिपाए रखा
- AWS पर 8 ECS tasks operate किए जा रहे थे
- हर task 5 backend instances run करता था
- users potentially 40 अलग-अलग IDs में से किसी एक तक पहुंच सकते थे
- दिन में main branch पर सीधे 10–20 commits प्रतिदिन किए जाते थे, और हर बार नया backend deployment होता था
- हर deployment के साथ customers के लिए 40 नई IDs उपलब्ध हो जाती थीं
- रात में commits और deployments रुकने पर हर server की single ID जल्दी exhaust हो गई
- शुरुआत में subscription के लिए उपलब्ध servers करीब 40 थे, लेकिन समय के साथ लगभग 0 के करीब पहुंच गए
loss का scale और बाद की actions
- loss को
50 emails/day x 5 days x $40/monthसे calculate कर monthly $10,000 revenue loss अनुमानित किया गया- यह calculation केवल complaint भेजने वाले users पर आधारित है
- cause खोजने में 5 दिन, बहुत सारे emails, सैकड़ों Sentry logs, Stripe engineer के साथ लंबी Discord conversation, और पांच core files की review लगी
- cause मिलने के बाद Adam ने जल्दी से fix submit किया
- इसके बाद strong unit/integration tests, alerts और logging जोड़े गए
- यह घटना दिखाती है कि human error, insufficient testing, code copying और main पर direct push मिलकर छोटी-सी एक line को भी बड़े revenue loss में बदल सकते हैं
2 टिप्पणियां
अरे, AI द्वारा अपने-आप जनरेट किया गया कोड तो हमेशा review करना चाहिए, उसे वैसे का वैसा क्यों इस्तेमाल करते हैं?
Hacker News की रायें
मॉनिटरिंग की कमी ने 10,000 डॉलर डुबो दिए। ऐप लगातार और बड़ी मात्रा में database exceptions फेंक रहा था, लेकिन किसी को कोई alert नहीं मिला
अगर ऐसा alert होता, तो यह 5 दिन की जांच नहीं बल्कि 5 मिनट की जांच में खत्म हो जाता। अगर alerting system ठीक नहीं किया गया, तो असल में कुछ भी ठीक नहीं हुआ
जब सब कुछ ठीक चल रहा हो तो programming आसान होती है; मुश्किल हिस्सा समस्याओं को handle करने वाला होता है
जिस पल paid customers आने लगते हैं, उसी पल से logging, monitoring, alerting, security आदि संभालने का ज्ञान और अनुभव रखने वाला व्यक्ति चाहिए। DevOps को amateur तरीके से नहीं लेना चाहिए
लेकिन database में error logging और alerting न होना असली पागलपन है। यह 20 साल पुराना legacy code नहीं है, बल्कि नया product है; और यह उस दौर का code भी नहीं है जब DB errors को data validation की तरह इस्तेमाल किया जाता था
Blog post 404 दिखा रहा था, इसलिए Web Archive link छोड़ रहा हूं
https://web.archive.org/web/20240610032818/https://asim.bear...
लेखक ने एक महत्वपूर्ण correction जोड़ा था: यहां की practices बेहद खराब और शर्मनाक स्तर की थीं, और बाद में उन्होंने मजबूत unit/integration tests और alerting/logging जोड़े। आखिरकार यह human error था, और पीछे मुड़कर देखने पर साफ तौर पर टाला जा सकने वाला मामला था
उन्होंने यह भी जोड़ा कि यह कंपनी के शुरुआती कुछ हफ्तों में भारी time pressure के बीच हुआ था, और इसे production में bug reproducibility की अजीब प्रकृति वाली एक मजेदार कहानी की तरह देखा जाए
मूर्खतापूर्ण गलती तो है, लेकिन इंसान—चाहे व्यक्ति हों या समूह—मूर्खतापूर्ण गलतियां करते ही हैं
https://0912i390129ionkjan.bearblog.dev/how-a-single-chatgpt...
https://webcache.googleusercontent.com/search?q=cache%3Ahttp...
गलती तुरंत दिख रही थी। टीम के प्रति सम्मान है, लेकिन इसका ChatGPT से खास लेना-देना नहीं है; इसका ज्यादा संबंध उस programming model के इस्तेमाल से है जिससे टीम पर्याप्त परिचित नहीं थी
मान लें कि code review से यह निकल भी गया होता, तब भी 5 मिनट में सेट किए जा सकने वाले monitoring tools होते तो शायद यह पकड़ में आ जाता
“LLM का इस्तेमाल करते हुए programming error किया, और quality assurance न होने से 10,000 डॉलर खर्च हो गए” जैसा title executives से “अगर ChatGPT गड़बड़ कर दे तो हमारा exposure कितना होगा?” जैसी प्रतिक्रिया नहीं निकलवाता। LinkedIn पर इस लेख को पोस्ट करने वाले middle और senior managers की संख्या बहुत बड़ी होगी
LLM “गलती” नहीं कर सकते। वे deterministic नहीं होते, न वे reason करते हैं, न सोचते हैं, न logic execute करते हैं। वे statistical probabilities का इस्तेमाल करने वाले बेहद चमकदार word-salad generators हैं, और उनकी output सही या accurate होगी इसकी कोई guarantee नहीं होती, इसलिए परिभाषा के हिसाब से “गलती” कहना भी ठीक नहीं है
सुधार: लेख को स्पष्ट कारणों से भारी downvote मिलने के बाद उसकी ranking अचानक ऊपर चली गई, जिसका मतलब लगता है कि moderator ने उसे boost किया: https://hnrankings.info/40627558/
मजेदार है कि नियमों के हिसाब से जिसका title बदल देना चाहिए था, ऐसा clickbait लेख moderator से boost हो गया। ऊपर से लेखक का Y Combinator company से जुड़ा होना भी शायद पूरी तरह संयोग ही होगा: https://news.ycombinator.com/item?id=40629998
primary key के UUID generation में
str(uuid.uuid4())नहीं, बल्कि callableuuid.uuid4को सीधे इस्तेमाल करना चाहिए, और SQLAlchemy value बनाते समय function को call करता है। date default के लिए कहा किserver_default=text("(now())")उम्मीद के मुताबिक काम न करे, इसलिएfunc.now()इस्तेमाल करें;uuidऔर SQLAlchemy केtextimports भी check करने को कहा, और timezone handling के लिएDateTime(timezone=True)पर भी विचार करने को कहाबाद में corrected code के रूप में उसने
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()), unique=True, nullable=False)दिया, और यहांlambda:जोड़ने से समस्या ठीक हुईuuid.uuid4()को Prisma जैसी किसी चीज़ की schema definition जैसा समझ लिया होगा। इसलिए यह bug अपने-आप में चौंकाने वाला नहीं है, और मैं भी शायद यही गलती कर सकता थाफिर भी
kubectl logsएक बार चलाने से यह तुरंत पकड़ में आ जाता। और फिर Next.js और Prisma से Python पर जाना? क्यों?गलती अपने-आप में समझ आती है। ChatGPT के बिना code लिखते हुए भी यह अपेक्षाकृत आसानी से छूट सकती है
लेकिन पहली failure के बाद यह पकड़ी क्यों नहीं गई, यह समझ नहीं आता। क्या इस company में logging नहीं थी? backend UUID reuse करने की कोशिश कर रहा है, यह error देखकर तुरंत साफ हो जाना चाहिए था
Stringकी जगह callable object देने वाली function में गलती से string दे देना आम बात है। अगर ORM इस्तेमाल नहीं किया होता तो शायद यह specific problem रुक जाती, लेकिन यह ORM को लेकर मेरा निजी bias भी हो सकता है। database के अलावा दूसरे contexts में भी ऐसे bugs आसानी से हो सकते हैंजो लोग पूरे confidence से कहते हैं कि वे यह bug जरूर पकड़ लेते, वे या तो मुझसे कहीं बेहतर engineers हैं, या ज्यादा संभावना यह है कि वे अपनी क्षमता को लेकर थोड़ा भ्रम में हैं
हालांकि logs न होना या logs न देखना वाकई समझना मुश्किल है। ECS हो तो Duplicate Key exception बिना extra configuration के CloudWatch तक propagate हो जाना चाहिए था; समझ नहीं आता कि ऐसा नहीं हुआ, या हुआ लेकिन रात भर कौन-सी exception आई, यह किसी ने check ही नहीं किया
ऐसी स्थिति में यह पूछना उपयोगी होता है कि detection देर से क्यों हुई और diagnosis में इतना समय क्यों लगा
इंसानों द्वारा लिखे गए code में भी मैंने यही गलती कई बार देखी है। खासकर React / TypeScript / JavaScript में कोई न कोई lambda भूल जाता है
ब्लॉग पोस्ट समस्या की असली जड़ ठीक से समझाए बिना सीधे ChatGPT पर दोष डालती हुई लगती है। जल्दी में काम करना, बड़े बदलाव या peer review के बिना commit को main में डालना—ऐसे ही मामलों में यह होता है
असली समस्या यह है कि अगर आप जल्दबाज़ी करते हैं, shortcut लेते हैं, और पर्याप्त testing व peer code review नहीं करते, तो errors आते हैं। अलग-अलग signup options आज़माने वाला एक test भी होता तो शायद यह तुरंत पकड़ में आ जाता
ऐसे व्यक्ति को financially important code के पास रखेंगे तो इसी तरह की समस्याएँ आएँगी, और जिसने लगभग बिना tests के वह code deploy करने का फैसला किया, उसके judgment पर सवाल उठेगा
हैरानी है कि इस case के लिए कोई lint rule नहीं था
उम्मीद है ऐसा नहीं हुआ होगा
“मूल project full-stack NextJS था, लेकिन पहले मैं सब कुछ Python/FastAPI में migrate करना चाहता था” वाला हिस्सा आंखें खोलने वाला है
जिनके पास customer भी नहीं हैं, ऐसा startup rewrite को कैसे justify करता है, समझ नहीं आता
customers हों या न हों, इतने शुरुआती समय में, असल में Node से Python की horizontal move क्यों करनी है, समझ नहीं आता। अगर सैकड़ों customers हों और Go जैसी किसी चीज़ पर shift करना हो तो शायद थोड़ा समझ में आए, लेकिन तब भी सवाल रहेगा
उदाहरण के लिए ढेर सारे DTO objects बनाने पड़ते हैं, लेकिन AutoMapper मेरे version combination और project settings में काम नहीं करता, और Entity Framework व JSON serialization/deserialization से जितना मिलता है उससे ज्यादा दर्द मिलता है
बेशक इसे धीरे-धीरे हल किया जा सकता है। docs में गहराई से उतरना, कुछ hacks मिलाना, packages upgrade करना और settings दोबारा लिखना—ये सब किया जा सकता है। लेकिन इंसान होने के नाते मन करता है कि रूपक वाले petrol can से सब जला दें और दूसरा system बेहतर बनाएं। बेशक असल में वह बेहतर नहीं होता, बस दूसरे pain points आ जाते हैं, और हो सकता है वह पहले system वाला सब काम करे भी नहीं या ठीक से न करे
काम पर भी जब legacy या cumbersome system दिखता है, तो यही impulse आता है। rewrite करने को चिल्लाते दिमाग पर काबू पाने के लिए सक्रिय और लगातार प्रयास चाहिए। कभी-कभी rewrite या containers अपनाने जैसे architecture changes सफल भी होते हैं, लेकिन अक्सर वे आग में कूदने या अंतहीन काम में बदल जाते हैं
system operations या दूसरे developers के developer experience में सुधार होगा, इसका बहुत मजबूत भरोसा न हो तो उस impulse के आगे न झुकना ही अच्छा है
ChatGPT ने तो उल्टा app से कमाया गया पैसा बनाने में मदद की। क्योंकि ChatGPT के बिना वे इसे implement कर पाने में सक्षम नहीं थे
coding, debugging, logging, monitoring न कर पाने की skill कमी ने 10 हजार dollar उड़ाए, और इस कहानी में ChatGPT का net effect positive है
हर commit message में emoji है। बंदर, banana, rocket, fireworks—क्या नहीं है
https://grook.ai/share?id=e269e88a7b1a71eff4f176c864b30161&x...
original full-stack NextJS था, और Python/FastAPI में backend migrate करते समय वे Prisma/Typescript के database models को Python/SQLAlchemy में translate कर रहे थे। लिखा है कि यह काम boring था, और ChatGPT इसे काफी अच्छा करता दिखा, इसलिए लगभग पूरी migration में उसका इस्तेमाल किया
अगर शुरू से ChatGPT न होता तो वे शायद यह upfront migration करने की कोशिश ही नहीं करते, इसलिए net effect positive कहना मुश्किल है। existing stack में बेहतर error logging रही भी हो सकती थी, नहीं भी; और अपने लिखे code की structure बेहतर समझ होने से उसकी जरूरत कम भी पड़ी हो सकती थी
monetization चालू करने से पहले “सारा code दूसरी बार फिर से लिखने” का फैसला खुद भी दिलचस्प है
“मैं पहले यह कहना चाहता हूं कि यहां की practices खराब थीं और इससे बचा जा सकता था। यह एक ऐसे अलग समय की बात है जब बहुत ज्यादा time pressure था। कृपया इसे ध्यान में रखकर पढ़ें” ऐसा वाक्य है
ऐसी constraints की वजह से software subscriptions डरावनी लगती हैं
race condition की वजह से user से दो बार charge भी हो चुका है। इसलिए पैसे से जुड़े timeout या error देखते ही मैं इतना paranoid हो जाता हूं कि पहले मान लेता हूं payment हो गई है और बाद में फिर check करता हूं
TypeScript और Python में लिखा code, Next.js जैसे framework, AWS tasks के 8 सेट में हर एक पर 5 instances चला रहे थे, और revenue सिर्फ 40 डॉलर था, development time बस कुछ हफ्ते?
आखिर चल क्या रहा था, समझ नहीं आता। time constraint की वजह से code गड़बड़ था—यह सुधार करने की बात मान भी लें, तो असल में languages के बीच refactoring और बिना किसी वजह के distributed system बनाने में time खर्च करना और भी खराब है।
features और बेतुकी technical complexity को साथ-साथ juggle करना—यह self-harm complexity है। पता नहीं क्या सोच रहे थे।
edit: यह YC Summer 2023 कंपनी है, लेकिन Summer 2024 में भी product शायद waitlist के पीछे ही है। शायद इसलिए कि वे इसे Rust में फिर से लिख रहे हैं।
लगता है Python में कुल मिलाकर 1000 lines भी नहीं लिखी होंगी, फिर भी समस्या ठीक से पकड़ ली।
Python में एक defect है कि उसने Common Lisp की evaluation strategy ठीक से copy नहीं की। optional function arguments के default value expression में अगर
foo=obj.whatever()जैसा argument हो, तोobj.whatever()function call के समय नहीं, बल्कि function definition process होने के समय evaluate होता है।शक है कि efficiency के लिए जानबूझकर ऐसा किया गया। Python में एक और defect है: list जैसे common objects के लिए असली literal syntax नहीं है।
[1, 2, 3]literal नहीं, constructor जैसा है; हर बार evaluate होने पर नई list बनानी और values भरनी पड़ती हैं।designer शायद नहीं चाहता था कि
list=[]जैसा parameter, argument omit होने पर हर बार नई खाली list बनाए। Lisp में'(1 2 3)और'()असली literals हैं और हर reference पर उसी object को point करते हैं। programmer default value expression के तौर पर(list 1 2 3)लिखना है या'(1 2 3), यह चुन सकता है।पहला
[1, 2, 3]की तरह हर बार नया mutable object बनाता है, और दूसरा लगभग निश्चित रूप से वही object return करता है और उसे भरोसेमंद व portable तरीके से modify नहीं किया जा सकता। modern popular languages में Lisp की ज्यादातर features आ चुकी हैं, इसलिए यह ऐसा joke लगता है कि खोने को कुछ नहीं।foo=obj.whatever()मेंobj.whatever()function call के समय नहीं बल्कि function definition process होने के समय evaluate होता है—यह बात सही हो ही नहीं सकती लगती।अगर
.whatever()object initialization के बाद बदलने वाली internal state पर निर्भर हो, तो क्या होगा, समझ नहीं आता।