31 पॉइंट द्वारा darjeeling 2026-04-10 | 4 टिप्पणियां | WhatsApp पर शेयर करें

ultrathink.art एक ऐसा ई-कॉमर्स शॉपिंग मॉल है जिसे AI एजेंट स्वायत्त रूप से चलाते हैं। प्रोडक्ट डिज़ाइन, ऑर्डर प्रोसेसिंग और ब्लॉग लेखन तक सब कुछ AI संभालता है। यह लेख उस शॉपिंग मॉल को वास्तविक Stripe भुगतान तक संभालने वाले production environment में SQLite के साथ चलाने के अनुभवों को समेटता है.


संरचना: 4 फाइलें, 1 वॉल्यूम

production environment में कुल 4 SQLite डेटाबेस चलाए जाते हैं — primary (ऑर्डर·प्रोडक्ट·यूज़र), cache (Rails cache), queue (background jobs), cable (Action Cable) — और ये सभी एक ही Docker volume में संग्रहीत होते हैं।

Rails 8 ने SQLite को पहली पसंद बना दिया, और वास्तव में deployment को सरल बनाना, connection pool management की ज़रूरत न होना, अलग DB server न होना जैसे फायदे मिले।


WAL मोड concurrency कैसे संभव बनाता है

SQLite का डिफ़ॉल्ट journal mode लिखते समय पूरे DB को lock कर देता है, इसलिए बहुत अधिक concurrent requests वाले web app के लिए यह उपयुक्त नहीं है। WAL (Write-Ahead Logging) mode में writes एक अलग -wal फाइल में जोड़ी जाती हैं और reads मुख्य फाइल का उपयोग जारी रखते हैं, इसलिए कई reads और एक single write एक साथ संभव होते हैं। Rails 8 SQLite में WAL mode को डिफ़ॉल्ट रूप से सक्षम करता है।


घटना: 2 ऑर्डर गायब हो गए

4 फ़रवरी को 2 घंटे के दौरान main पर 11 commits push किए गए। हर push पर Kamal का blue-green deployment चला, जिससे पुराना container और नया container एक ही WAL फाइल को एक साथ खोलने वाला overlap period बन गया। 11 deployments के overlap होने से ऐसी स्थिति बनी कि container A draining में था, तभी B शुरू हो गया, और B पूरी तरह तैयार होने से पहले C का deployment शुरू हो गया।

ऑर्डर 16 और 17 के लिए Stripe में भुगतान सफल हुआ और ग्राहकों के खातों से पैसा भी कट गया, लेकिन DB में कोई record नहीं बचा। sqlite_sequence से जाँच करने पर auto-increment counter 17 दिखा रहा था, जबकि वास्तविक rows सिर्फ 15 थीं।


समाधान: deployment की गति धीमी करो

समाधान तकनीकी नहीं बल्कि प्रक्रियात्मक था। संबंधित बदलावों को एक साथ बाँधकर deploy करना, और तेज़ी से लगातार push करने से बचना — इन नियमों को AI एजेंट्स द्वारा पालन किए जाने वाले governance file (CLAUDE.md) में स्पष्ट रूप से लिखा गया।

यह SQLite की समस्या नहीं बल्कि deployment pipeline की समस्या है। PostgreSQL TCP socket के जरिए connect होता है, इसलिए नया container भी उसी DB server से जुड़ता है और write order को DB engine संभालता है। SQLite shared Docker volume के filesystem lock पर निर्भर करता है, और जब containers overlap करते हैं तो यही व्यवस्था टूट जाती है।


sqlite_sequence: forensic tool की तरह उपयोग करना

sqlite_sequence टेबल SQLite में सबसे कम आंके गए debugging tools में से एक है। बाद में delete की गई rows के लिए भी यह अतीत में assign किया गया सबसे बड़ा auto-increment value याद रखती है। अगर मौजूदा row count और sequence value के बीच का अंतर उम्मीद से ज़्यादा हो, तो यह संकेत है कि कहीं rows गलत तरीके से delete हुई हैं।


वे छिपे हुए pitfalls जिनकी बात कोई नहीं करता

PostgreSQL developers आदतन इस्तेमाल करने वाला ILIKE, SQLite में syntax error देता है। उसकी जगह LOWER(name) LIKE इस्तेमाल करना पड़ता है। json_extract अगर value को number के रूप में stored पाए, तो वह integer लौटाता है और string comparison के समय चुपचाप fail हो जाता है। kamal app exec हर बार नया container बनाता है, और 2GB RAM वाले server पर इसे एक साथ दो बार चलाने पर OOM killer web process को मार देता है।


अगर फिर से चुनना पड़े, तो क्या SQLite ही चुनेंगे?

हाँ। एक single server पर मध्यम write load के लिए SQLite पूरी infrastructure complexity को लगभग खत्म कर देता है। backup के लिए sqlite3 .backup command ही काफी है (यह WAL mode और concurrent writes को सुरक्षित रूप से संभालता है)। जिस दिन horizontal scaling या वास्तविक multi-writer concurrency की ज़रूरत होगी, उस दिन PostgreSQL पर migrate किया जा सकता है। Rails उस transition को आसान बना देता है।


मूल लेख: ultrathink.art Blog, 2026.04.03

4 टिप्पणियां

 
click 2026-04-11

इन्फ्रास्ट्रक्चर की complexity की समस्या कितनी भी हो, फिर भी shopping mall जैसी जगहों में जहाँ concurrent writes बहुत ज़्यादा चाहिए होती हैं, क्या शुरुआत से sqlite का इस्तेमाल न करना ही बेहतर विकल्प नहीं होगा?
यहाँ तक कि अगर इसे Docker से बनाया गया था, तो PostgreSQL setup की infra complexity भी इतनी ज़्यादा नहीं होती।
मुझे लगता है कि इसे Rails में बनाने की वजह से ecosystem पहले से sqlite इस्तेमाल करने की दिशा में ढला हुआ था, इसलिए इसे अच्छा विकल्प मानने के लिए प्रेरित किया गया।
order miss होने जैसी गंभीर error हुई, और shopping mall जैसी जगहों में जहाँ concurrent writes बहुत ज़्यादा चाहिए होती हैं, क्या शुरुआत से sqlite का इस्तेमाल न करना ही बेहतर विकल्प नहीं होगा, भले ही pg जैसी concurrent write DB में भी कुछ समस्याएँ हों?
मुझे लगता है कि Rails में बनाने की वजह से ecosystem पहले से sqlite इस्तेमाल करने की दिशा में ढला हुआ था, इसलिए इसे अच्छा विकल्प मानने के लिए प्रेरित किया गया।
order miss होने जैसी गंभीर error हुई, और इसका मूलभूत समाधान तो pg जैसी concurrent write DB का इस्तेमाल करना है।
तकनीकी पसंद की वजह से sqlite को लगातार इस्तेमाल करने पर अड़े रहना मुझे एक engineer के रूप में भरोसा कम करने वाला बयान लगता है।
यह मुझे उस resume-driven development के उलटे version जैसा लगता है, जहाँ ज़रूरत न होने पर भी k8s लगाया जाता है, replica 1 वाला HPA बनाया जाता है, और अच्छे-भले monolith को MSA में बदला जाता है।

 
okxrr 2026-04-12

समस्या यह है कि container में चलाते समय volume settings गलत थीं, यह नहीं कि concurrent writes सपोर्ट नहीं होने की वजह से दिक्कत हुई। अगर आप लेख दोबारा पढ़ें, तो उसमें लिखा है कि concurrent writes न होने की बात busy timeout से पर्याप्त रूप से कवर हो जाती है। volume settings का समाधान
ipc=host से हो जाएगा।

आखिरकार postgres को ऑपरेट करना ही पड़ता है, जबकि sqlite में कहीं भी सिर्फ app binary deploy कर दें तो काम हो जाता है।

काफी सारे operational experiences और failures जमा होने के बाद ही sqlite चलन में आने लगा है, और
लेख में भी साफ़ लिखा है कि concurrent writes बिल्कुल भी समस्या नहीं हैं।

 
darjeeling 2026-04-12

असल में कई तरह की settings ही करनी होती हैं, लेकिन आखिरकार अनुभव तो चाहिए ही, हाहा। खैर, मुझे ऐसे लेख अच्छे लगते हैं।

 
darjeeling 2026-04-11

बिल्कुल, इसलिए ऐसे लेख कभी-कभी सामने आते रहें तो और भी अच्छा लगेगा।