हमने beads v1.0.0 सपोर्ट शिप किया। इसमें एक rollback, एक flock बग और 6 hotfixes लगे।
2 अप्रैल को beads ने v1.0.0 शिप किया। मुख्य फ़ीचर था embedded Dolt: एक ज़ीरो-कॉन्फ़िग बैकएंड जो डेटाबेस को in-process चलाता है, कोई अलग सर्वर मैनेज करने की ज़रूरत नहीं। सोलो डेवलपर्स के लिए यह bd init और बस हो गया का वादा था। कोई ports नहीं, कोई daemons नहीं, कोई कॉन्फ़िगरेशन नहीं।
हमने तुरंत Beadbox में सपोर्ट जोड़ना शुरू किया। छह hotfix releases, एक पब्लिक rollback और bd के सोर्स कोड में गहरी खोज के बाद, हम दूसरी तरफ़ एक resilience लेयर के साथ निकले जो हमें शायद महीनों पहले बनानी चाहिए थी।
सब कुछ टूटने से पहले की सुबह
दिन साफ़ शुरू हुआ। हमने कोडबेस में dead code हंट चलाई थी और v0.20.0 शिप किया था जिसमें 5,350 लाइनें हटाई गईं और cold launch में 2 सेकंड का सुधार हुआ। बयालीस beads बंद किए। अच्छी सुबह।
फिर हमने bd को 0.63.3 में अपग्रेड किया, जो beads v1.0.0 के embedded Dolt बैकएंड पर बना पहला release था।
Beadbox डेटाबेस नहीं ढूंढ पा रहा था। Embedded मोड डेटा को .beads/dolt/ के बजाय .beads/embeddeddolt/ में स्टोर करता है। डेटाबेस का नाम भी बदल गया, hardcoded beads से metadata.json से पढ़े गए प्रोजेक्ट प्रीफ़िक्स में। और bd sql, जिसे हमारा WebSocket सर्वर DOLT_HASHOF_TABLE के ज़रिए O(1) change detection के लिए इस्तेमाल करता था, embedded मोड में बिल्कुल सपोर्टेड नहीं है।
पहले दस मिनट में तीन assumptions टूट गए।
एक दिन में छह releases
खोजो, ठीक करो, शिप करो, फिर से खोजो।
v0.20.1 ने OS keychain का उपयोग करके credential persistence जोड़ा (छह beads का काम पहले से प्रगति में), एक custom status filter बग ठीक किया और Windows-specific समस्याएं पैच कीं।
v0.20.2 ने Beadbox को metadata.json से dolt_database पढ़ना सिखाया ताकि वह rename हुए डेटाबेस को ढूंढ सके।
v0.20.3 ने embedded mode guards जोड़े। हर bd sql कॉल को एक चेक के साथ wrap किया: अगर हम embedded मोड में हैं, तो डायरेक्ट SQL queries के बजाय CLI-based polling पर fall back करो। getDoltDir फ़ंक्शन ने पहले embeddeddolt/ में देखना सीखा।
v0.20.4 ने embedded layout के लिए --db path normalization ठीक किया। पुरानी directory structure के साथ काम करने वाले paths नई के साथ टूट गए।
हर fix अगली समस्या को सामने लाता था।
Flock
v0.20.4 के बाद, हमने सोचा कि हम स्थिर हैं। फिर हमने एक सिंपल concurrency टेस्ट चलाया: एक ही समय में पांच bd list कॉल्स।
चार में से चार फ़ेल हुए।
Embedded Dolt हर कमांड की पूरी lifetime के लिए डेटाबेस पर एक exclusive file lock (flock) acquire करता है। PersistentPreRun से PersistentPostRun तक, कुछ और उसे छू नहीं सकता। यह design by है। इसके बिना, concurrent engine initialization एक nil-pointer panic cause करता है (beads#2571)। Flock crash रोकता है। लेकिन इसका मतलब यह भी है कि embedded मोड में bd effectively single-process है।
Beadbox single-process नहीं है। हमारा WebSocket सर्वर हर सेकंड changes के लिए poll करता है। UI पेज लोड पर कई server actions fire करता है। एक user जो app में क्लिक कर रहा है जबकि background poller चल रहा है, concurrent bd calls जनरेट करेगा। Flock पहले को छोड़कर सब को ब्लॉक करता है।
DoltHub ब्लॉग पोस्ट ने embedded implementation के बारे में intended behavior बताया: concurrent callers को "exponential backoff के साथ naturally queue up" करना चाहिए। लेकिन arch ने shipped source code की समीक्षा की और पाया कि bd TryLock को LOCK_NB (non-blocking) के साथ use करता है। यह wait नहीं करता। यह तुरंत fail हो जाता है। दो lock layers हैं: bd का flock ऊपर, और Dolt का driver-level backoff नीचे। पहली layer दूसरी को short-circuit करती है। Retry logic कोडबेस में मौजूद है, लेकिन कभी execute नहीं होती क्योंकि flock connection को reject कर देता है इससे पहले कि Dolt का backoff चलने का मौका मिले।
Fix (read operations के लिए shared locks via FlockSharedNonBlock) bd के source में मौजूद है। बस अभी wired up नहीं है।
Beadbox यही समस्या हल करता है।
आपकी पूरी agent fleet क्या कर रही है, real-time में देखें।
हम moving target के खिलाफ़ hotfixes शिप करते रह सकते थे, या पीछे हटकर एक proper resilience layer बना सकते थे। हमने पीछे हटने का चुनाव किया।
सभी v0.20.x releases पब्लिक repo से हटा दिए गए। v0.19.0 recommended version के रूप में वापस आया। हमने एक discussion पोस्ट की जिसमें बताया कि क्या हुआ और क्या करना है, और beadbox.app पर एक banner जोड़ा। फ़ैसले से लेकर पूरा होने तक तीस मिनट।
हर घंटा जो एक टूटा release पब्लिक रहता है, वह एक घंटा है जहां कोई इसे डाउनलोड करता है, flock issue से टकराता है और प्रोडक्ट को दोष देता है। हम rollback समझाना पसंद करेंगे बजाय किसी और की ख़राब पहली experience को debug करने के।
हम अकेले नहीं थे
जब हम debug कर रहे थे, एक beads user Kevin ने beads#2938 पोस्ट किया: "Beads feels painful to use." उसने 9.5 घंटे उन्हीं issues को debug करने में बिताए थे जिनमें वही embedded-to-server confusion शामिल था जो हम face कर रहे थे। v1.0.0 में अपग्रेड ने चुपचाप उसके workspace को server mode से embedded mode में switch कर दिया था (beads#2949), उसके existing issues को एक fresh empty database के पीछे छिपा दिया।
9.5 घंटे। एक experienced user, कोई नया नहीं। अगर beads को अच्छी तरह जानने वाले किसी व्यक्ति का यह अनुभव है, तो समस्या user में नहीं है। समस्या migration path में है।
v0.21.0 के लिए हमने क्या बनाया
Individual failures को patch करने के बजाय, हमने एक layer बनाई जो lock contention को एक normal operating condition मानती है।
Exponential backoff के साथ flock retry. हर bd CLI कॉल 5 बार तक retry करती है, attempts के बीच 100ms से 1.6 सेकंड। lib/bd.ts में एक जगह रहता है, इसलिए हर command इसे मुफ़्त में पाता है। यह common case को cover करता है: दो calls टकराती हैं, एक थोड़ा wait करती है, दोनों succeed होती हैं।
Graceful degradation UI. Lock contention का मतलब अब error screen नहीं है। App stale data दिखाती है एक refresh indicator के साथ। अगर contention 30 सेकंड से ज़्यादा बनी रहती है, तो एक amber banner स्थिति समझाता है। जब lock clear होता है, banner गायब हो जाता है और data automatically refresh हो जाता है।
Auto-promote suggestion. बार-बार contention होने पर server mode में migrate करने का सुझाव trigger होता है: backup, --server के साथ reinitialize, restore। एक click। यह सही जवाब है उन सबके लिए जो Beadbox को अन्य bd consumers के साथ चलाते हैं, और अब app यह बताती है बजाय आपको ख़ुद पता लगाने देने के।
Embedded mode detection.getDoltDirembeddeddolt/ चेक करता है और accordingly route करता है। bd sql calls guarded हैं। WebSocket pipeline embedded mode में CLI-based polling पर fall back करती है (धीमी, लेकिन single-process constraint का सम्मान करती है)।
हमने क्या सीखा
Embedded Dolt design से single-process है। यह bug नहीं है। Flock real panics रोकता है। कोई भी tool जो beads workspace को concurrently consume करता है, उसे access serialize करना होगा या server mode में चलना होगा। Beadbox के लिए, server mode सही default है। Embedded हल्के उपयोग के लिए काम करता है जहां retry layer occasional collisions absorb करती है।
Docs ने intent describe किया, implementation नहीं। DoltHub blog ने backoff कहा। Code ने TryLock with LOCK_NB कहा। हमने समय बिताया यह मानते हुए कि concurrent reads काम करनी चाहिए क्योंकि documentation ऐसा कहती थी। Source पढ़ने से confusion मिनटों में दूर हो गया। जब behavior docs से match नहीं करता, code पढ़ो।
Ship करने से पहले concurrency test करो। हमने concurrent bd calls v0.20.4 public होने तक नहीं चलाए। for i in {1..5}; do bd list & done; wait ने किसी भी release से पहले flock issue पकड़ लिया होता। पांच सेकंड की testing ने हमें rollback से बचाया होता।
जल्दी rollback करो। आगे बढ़ते रहने की instinct मजबूत होती है। आप करीब हैं, fix दिख रहा है, एक और release। लेकिन हर टूटा release जो public रहता है, वह trust withdrawal है जिसे आसानी से undo नहीं किया जा सकता। v0.19.0 पर वापस जाने ने हमें resilience layer को ठीक से बनाने की जगह दी बजाय इसे panicked increments में ship करने के।
अपने environment variables चेक करो। हमने BEADS_DIR के ग़लत workspace पर point करने की वजह से घंटे गंवाए। bd एक अलग database discover कर रहा था जो Beadbox monitor कर रहा था, और symptoms data corruption जैसे दिख रहे थे। अगर आपके bd commands unexpected results दें, तो किसी भी चीज़ से पहले env | grep BEADS करो।
वर्तमान स्थिति
v0.21.0 beads v1.0.0 सपोर्ट, resilience layer और OS keychain के ज़रिए credential persistence के साथ बाहर है। Release discussion में पूरी details हैं।
अगर आप beads v1.0.0 embedded mode पर हैं और intermittent failures हो रही हैं, तो v0.21.0 की retry layer इसे handle कर लेनी चाहिए। अगर आप Beadbox को उन tools के साथ चला रहे हैं जो same workspace access करते हैं, तो server mode में switch करें। Auto-promote flow इसे एक click में करता है।
और अगर आप Steve हैं या beads team में कोई जो यह पढ़ रहा है: reads के लिए shared flocks root cause को upstream fix कर देंगे। beads#2939 (Unix domain sockets) local connections को भी cleaner बनाएगा। हम जो भी ship होगा उसके आसपास build करते रहेंगे।
खुद आज़माएँ
पहले beads को coordination layer के रूप में शुरू करें। Visual oversight ज़रूरी हो तो Beadbox जोड़ें।
Beta में मुफ़्त। अकाउंट की ज़रूरत नहीं। Dolt के साथ नेटिव रूप से काम करता है।