प्रॉम्प्ट और संदर्भ
Node.js 24 का node:sqlite सिंक्रोनस APIs को एक्सपोज़ करता है। DatabaseSync एक SQLite कनेक्शन का प्रतिनिधित्व करता है; createSession() सत्र शुरू होने के बाद के परिवर्तनों को ट्रैक करता है; session.changeset() एक बाइनरी changeset लौटाता है; और लक्ष्य (target) एक कॉन्फ़्लिक्ट हैंडलर के साथ applyChangeset() को कॉल कर सकता है जो छोड़ (omit), बदल (replace) या निरस्त (abort) कर सकता है। एक ऑफ़लाइन क्लाइंट और एक सर्वर के बीच एक वृद्धिशील (incremental) सिंक्रोनाइज़ेशन प्रोटोकॉल डिज़ाइन करें।
समस्या डेटाबेस परिवर्तनों के सुरक्षित प्रसार (propagation) की है: प्राइमरी कीज़, पुराने-मानों की जाँच (old-value checks), कॉन्फ़्लिक्ट नीति, आइडेम्पोटेंसी, ट्रांज़ैक्शन सीमाएँ और अनुमतियाँ। एक changeset निष्पादन योग्य SQL नहीं है और यह स्वचालित क्रॉस-डेटाबेस मर्जिंग नहीं है।
साक्षात्कारकर्ता क्या परीक्षण कर रहा है
एक मजबूत उत्तर स्रोत जेनरेशन, विश्वसनीय डिलीवरी, परमाणु लक्ष्य अनुप्रयोग (atomic target application), और व्यावसायिक कॉन्फ़्लिक्ट निर्णयों को अलग करता है। Session के लाइफ़टाइम, changeset बनाम patchset, SQLITE_CHANGESET_DATA और संबंधित कॉन्फ़्लिक्ट प्रकारों, डुप्लिकेट एप्लिकेशन, स्कीमा इवोल्यूशन, और सिंक्रोनस DatabaseSync कार्य Node.js इवेंट लूप को कैसे प्रभावित करता है, इस पर प्रश्नों की अपेक्षा करें।
“क्रमबद्ध करें और अधिलेखित करें (Serialize and overwrite)” स्वतंत्र लक्ष्य अपडेट्स को खो देता है। हमेशा SQLITE_CHANGESET_REPLACE लौटाना व्यावसायिक डेटा को चुपचाप अधिलेखित (overwrite) कर देता है और शुद्धता का कोई तर्क प्रदान नहीं करता है।
पहले स्पष्ट करने योग्य प्रश्न
टोपोलॉजी और अधिकार (authority)
निर्धारित करें कि क्या सिंक्रोनाइज़ेशन एकतरफ़ा, द्विदिशीय (bidirectional), या मल्टी-क्लाइंट एकत्रीकरण है, और प्रत्येक इकाई के लिए कौन सी प्रतिलिपि आधिकारिक (authoritative) है। यदि दोनों पक्ष एक पंक्ति को संपादित करते हैं, तो मध्यस्थता करने के लिए एक संस्करण, डिवाइस आईडी, या व्यावसायिक ईवेंट का उपयोग करें; SQLite का डिफ़ॉल्ट कॉलबैक कोई व्यावसायिक नियम नहीं है।
संस्करण और स्कीमा जीवनचक्र
पुष्टि करें कि स्रोत और लक्ष्य स्कीमा, प्राइमरी कीज़ और कॉलम प्रकार साझा करते हैं। Changesets टेबल संरचना पर निर्भर करते हैं। पुराने changesets को फिर से चलाने से पहले माइग्रेशन पूरा होना चाहिए और उसमें एक प्रोटोकॉल संस्करण होना चाहिए।
लेटेंसी और सुरक्षा सीमा
पेलोड आकार, पुनः प्रयास विंडो (retry window), ऑफ़लाइन अवधि और संवेदनशील फ़ील्ड को स्पष्ट करें। बाइनरी पेलोड को अखंडता (integrity), प्रमाणीकरण (authentication), रीप्ले सुरक्षा और एन्क्रिप्शन की आवश्यकता होती है; वे विश्वसनीय SQL नहीं हैं।
30-सेकंड का उत्तर
“मैं प्रत्येक बैच को एक आईडी और एक स्रोत-संस्करण कर्सर निर्दिष्ट करता हूँ। स्रोत एक Session बनाता है, एक स्थानीय ट्रांज़ैक्शन कमिट करता है, और एक changeset निर्यात करता है। सर्वर स्कीमा, हस्ताक्षर, क्रम और आइडेम्पोटेंसी को मान्य करता है, फिर लक्ष्य ट्रांज़ैक्शन के अंदर applyChangeset को कॉल करता है। कॉन्फ़्लिक्ट हैंडलर डिफ़ॉल्ट रूप से निरस्त (abort) करता है और पंक्ति, कॉलम और कारण रिकॉर्ड करता है; छोड़ना (omit) या बदलना (replace) केवल स्पष्ट व्यावसायिक नीति द्वारा अनुमत है। एक सफल बैच टिकाऊ स्थिति (durable state) को आगे बढ़ाता है, विफलताएं सीमित बैकऑफ़ के साथ पुनः प्रयास करती हैं, और डुप्लिकेट बैच अपना पिछला परिणाम लौटाते हैं। बड़ा सिंक्रोनस SQLite कार्य एक वर्कर या कतार के पीछे चलता है ताकि यह Node के इवेंट लूप को ब्लॉक न करे।”
चरण-दर-चरण समाधान
चरण 1: ट्रैक करने योग्य बैच बनाएं
एक Session बनाने के बाद, एक बैच में एक स्पष्ट स्थानीय ट्रांज़ैक्शन स्कोप शामिल करें। batchId, स्रोत डिवाइस, प्रारंभिक कर्सर, स्कीमा संस्करण, changeset हैश और निर्माण समय रिकॉर्ड करें। session.changeset() से Uint8Array निर्यात करें, फिर Session को बंद करें या पुनः उपयोग करें ताकि असीमित इतिहास जमा न हो सके।
चरण 2: changeset या patchset चुनें
एक changeset में पुराने-मान की जानकारी शामिल होती है जो यह जाँचने के लिए उपयोगी होती है कि क्या लक्ष्य पंक्ति अभी भी अपेक्षाओं से मेल खाती है। एक patchset छोटा होता है लेकिन कम पुराने-मान का संदर्भ उजागर करता है। बैंडविड्थ और ऑडिट आवश्यकताओं के आधार पर चुनें; केवल पेलोड का आकार नैदानिक जानकारी (diagnostics) खोने का पर्याप्त कारण नहीं है।
चरण 3: मान्य करें और आइडेम्पोटेंट रूप से डिलीवर करें
TLS, डिवाइस पहचान और पेलोड हस्ताक्षर का उपयोग करें। आकार, हैश, स्कीमा संस्करण और मूल स्रोत को मान्य करें। batchId और स्रोत कर्सर द्वारा कुंजीबद्ध एक अद्वितीय रिकॉर्ड संग्रहीत करें; पहले से लागू किए गए बैच का डुप्लिकेट रिकॉर्ड किया गया परिणाम लौटाता है। बाद के बैचों को कर्सर क्रम में लागू करें, लापता बैचों को छोड़ने के बजाय प्रतीक्षा कतार (wait queue) में रखें।
चरण 4: एक ट्रांज़ैक्शन में लागू करें और कॉन्फ़्लिक्ट्स को वर्गीकृत करें
एक लक्ष्य ट्रांज़ैक्शन खोलें और applyChangeset को कॉल करें। कॉन्फ़्लिक्ट हैंडलर ऑडिट बफ़र में टेबल, प्राइमरी की, कॉन्फ़्लिक्ट प्रकार और लक्ष्य मान एकत्र करता है। डिफ़ॉल्ट रूप से SQLITE_CHANGESET_ABORT लौटाएं ताकि बैच परमाणु रूप से (atomically) रोलबैक हो जाए। केवल नीति-अनुमोदित फ़ील्ड ही OMIT या REPLACE लौटा सकते हैं, और यह निर्णय एक रीप्ले करने योग्य लॉग में होना चाहिए।
चरण 5: व्यावसायिक मर्ज को परिभाषित करें
फ़ील्ड-स्तरीय मर्ज करने योग्य डेटा टाइमस्टैम्प, मोनोटोनिक संस्करणों या सेट यूनियन का उपयोग कर सकता है। पैसा, इन्वेंट्री और अनुमतियां बिना सोचे-समझे मर्ज करने के लिए सुरक्षित नहीं हैं; उन्हें एक मानव कतार या मुआवज़ा घटना (compensation event) पर भेजें। निर्णय के बाद मूल changeset को म्यूटेट न करें। ऑडिट श्रृंखला को बनाए रखने के लिए पैरेंट बैच और निर्णय कारण युक्त एक चाइल्ड बैच उत्पन्न करें।
चरण 6: प्रकार और पूर्णांक परिशुद्धता (integer precision) को संभालें
Node.js और SQLite विभिन्न प्रकार के सेटों का समर्थन करते हैं। यदि कोई SQLite INTEGER जावास्क्रिप्ट की सुरक्षित पूर्णांक सीमा से अधिक है और readBigInts अक्षम है, तो इसे पढ़ने पर ERR_OUT_OF_RANGE थ्रो हो सकता है। BigInt, स्ट्रिंग्स या एक स्पष्ट सीमा पर मानकीकरण करें। BLOB मानों के लिए Uint8Array का उपयोग करें और मनमाने ऑब्जेक्ट्स को अस्वीकार करें।
चरण 7: सिंक्रोनस लागत को नियंत्रित करें
DatabaseSync कॉल सिंक्रोनस रूप से निष्पादित होते हैं। लंबे ट्रांज़ैक्शन, विशाल changesets, या लगातार applyChangeset कॉल इवेंट लूप को ब्लॉक कर सकते हैं। सिंक्रोनाइज़ेशन को एक वर्कर, अलग प्रक्रिया या नियंत्रित कतार में स्थानांतरित करें; प्रति बैच पेलोड और पंक्तियों को सीमित करें; लागू करने की अवधि, कॉन्फ़्लिक्ट्स, रोलबैक और कतार की आयु की निगरानी करें।
उच्च गुणवत्ता वाला नमूना उत्तर
मैं प्रत्येक सिंक्रोनाइज़ेशन बैच को एक अपरिवर्तनीय (immutable) घटना मानता हूँ। डिवाइस एक आईडी, कर्सर, स्कीमा संस्करण और हैश बनाता है; Session केवल एक कमिट किए गए स्थानीय ट्रांज़ैक्शन को कवर करता है; और changeset एक प्रमाणित, रीप्ले-संरक्षित चैनल पर प्रसारित होता है। सर्वर संरचना और क्रम को मान्य करता है, बैच आईडी द्वारा डिडुप्लिकेट करता है, और लक्ष्य SQLite ट्रांज़ैक्शन में applyChangeset को कॉल करता है।
कॉन्फ़्लिक्ट कॉलबैक डिफ़ॉल्ट रूप से निरस्त करता है, परमाणु रूप से रोलबैक करता है और प्राइमरी की, कॉन्फ़्लिक्ट प्रकार और लक्ष्य मान रिकॉर्ड करता है। इन्वेंट्री, पैसा और अनुमतियां सामान्य प्रतिस्थापन के बजाय व्यावसायिक विलय या मुआवजे के पास जाती हैं; केवल स्पष्ट रूप से सुरक्षित फ़ील्ड को छोड़ा या बदला जा सकता है। टिकाऊ बैच स्थिति कमिट के बाद ही कर्सर को आगे बढ़ाती है। चूँकि DatabaseSync सिंक्रोनस रूप से ब्लॉक करता है, मैं बड़े बैचों को एक वर्कर में चलाता हूँ और डुप्लिकेट डिलीवरी, लापता बैच, स्कीमा माइग्रेशन, पूर्णांक ओवरफ़्लो और प्रक्रिया-क्रैश रिकवरी का परीक्षण करता हूँ।
सामान्य गलतियाँ
- गलती: प्रत्येक सिंक पर लक्ष्य डेटाबेस को अधिलेखित (overwrite) करना। → यह क्यों विफल होता है: स्वतंत्र लक्ष्य अपडेट गायब हो जाते हैं। → समाधान: एक changeset भेजें, पुराने मानों की तुलना करें और निर्णय रिकॉर्ड करें।
- गलती: प्रत्येक कॉन्फ़्लिक्ट के लिए
REPLACEलौटाना। → यह क्यों विफल होता है: व्यावसायिक डेटा चुपचाप अधिलेखित हो जाता है। → समाधान: डिफ़ॉल्ट रूप से निरस्त करें और प्रति फ़ील्ड और इनवेरिएंट प्रतिस्थापन को अधिकृत करें। - गलती: आइडेम्पोटेंसी कुंजी के बिना प्रत्येक पुनः प्रयास के लिए एक नया बैच उत्पन्न करना। → यह क्यों विफल होता है: डुप्लिकेट एप्लिकेशन या कर्सर जंप बार-बार दुष्प्रभाव (side effects) उत्पन्न करते हैं। → समाधान: बैच आईडी, स्रोत कर्सर और एप्लिकेशन स्थिति के साथ डिडुप्लिकेट करें।
- गलती: मुख्य इवेंट लूप पर एक विशाल changeset लागू करना। → यह क्यों विफल होता है: सिंक्रोनस
DatabaseSyncकार्य HTTP और शेड्यूल किए गए कार्य को ब्लॉक करता है। → समाधान: इसे एक वर्कर या कतार में अलग करें और बैच आकार को सीमित करें।
अनुवर्ती प्रश्न और उत्तर
अनुवर्ती 1: आप patchset का उपयोग कब करेंगे?
जब बैंडविड्थ सीमित हो और मामूली कॉन्फ़्लिक्ट-ऑडिट आवश्यकताओं के साथ लक्ष्य के पास पर्याप्त संदर्भ हो, तब patchset का उपयोग करें। जब कॉन्फ़्लिक्ट्स की व्याख्या करने या ऑडिट योग्य मर्ज करने के लिए पुराने मानों की आवश्यकता हो, तब बड़े पेलोड को स्वीकार करते हुए changeset का उपयोग करें।
अनुवर्ती 2: क्या होगा यदि लक्ष्य स्कीमा में कोई कॉलम गायब है?
संगतता त्रुटि (compatibility error) के साथ बैच को अस्वीकार करें; एप्लिकेशन को मैपिंग का अनुमान न लगाने दें। लक्ष्य माइग्रेशन चलाएँ, स्कीमा संस्करण और प्राइमरी कीज़ सत्यापित करें, फिर पुनः चलाएँ। यदि कई संस्करणों को सह-अस्तित्व में होना चाहिए, तो मूल पेलोड को बनाए रखते हुए प्रोटोकॉल संस्करण द्वारा परिवर्तित करें।
अनुवर्ती 3: आप कॉन्फ़्लिक्ट कॉलबैक में दुष्प्रभावों (side effects) को कैसे रोकते हैं?
कॉलबैक केवल संरचित कॉन्फ़्लिक्ट डेटा एकत्र करता है और एक स्थिर निर्णय लौटाता है। यह बाहरी सेवाओं को कॉल नहीं करता है या अन्य तालिकाओं को म्यूटेट नहीं करता है। कमिट के बाद ऑडिट रिकॉर्ड या सूचनाएं लिखें ताकि रोलबैक बाहरी स्थिति को असंगत न छोड़ सके।
अनुवर्ती 4: सीधे SQL क्यों नहीं भेजते?
SQL में स्रोत के पुराने मानों, स्कीमा संदर्भ और बैच सीमाओं का अभाव होता है। पुनः प्रयास विश्वसनीय रूप से यह निर्धारित नहीं कर सकते हैं कि यह लागू किया गया था या नहीं, और अनधिकृत कथन लक्ष्य तक पहुँच सकते हैं। SQLite-जनरेटेड changesets लक्ष्य पर प्रत्येक कॉन्फ़्लिक्ट को संसाधित कर सकते हैं, जिससे वे एक बेहतर नियंत्रित-सिंक प्रिमिटिव बन जाते हैं।
अनुवर्ती 5: आप पूर्णांक और BLOB प्रोटोकॉल समानता को कैसे सत्यापित करते हैं?
सबसे बड़े सुरक्षित पूर्णांक, एक सीमा से बाहर के पूर्णांक, ऋणात्मक, NULL, UTF-8 टेक्स्ट और बाइनरी पेलोड के लिए क्रॉस-लैंग्वेज फिक्स्चर बनाएं। प्रत्येक के लिए SQLite प्रकार, Node रीड/राइट विकल्प, और क्रमबद्ध प्रतिनिधित्व रिकॉर्ड करें, फिर पुष्टि करें कि रीप्ले से पहले और बाद में बाइट्स और मान मेल खाते हैं।