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

अभी कोई टिप्पणी नहीं है.

अभी कोई टिप्पणी नहीं है.