30 अप्रैल 2025·8 मिनट पढ़ने में

ऑफ़लाइन-प्रथम मोबाइल ऐप बैकग्राउंड सिंक: टकराव, पुन:प्रयास, UX

स्पष्ट टकराव नियम, पुनःप्रयास लॉजिक और नेटिव Kotlin व SwiftUI ऐप्स के लिए सरल पेंडिंग चेंज UX के साथ ऑफ़लाइन-प्रथम मोबाइल ऐप बैकग्राउंड सिंक की योजना बनाएं।

ऑफ़लाइन-प्रथम मोबाइल ऐप बैकग्राउंड सिंक: टकराव, पुन:प्रयास, UX

समस्या: उपयोगकर्ता ऑफ़लाइन संपादित करते हैं और जबकि वास्तविकता बदल जाती है

कोई उपयोगकर्ता एक अच्छे कनेक्शन के साथ काम शुरू करता है, फिर लिफ्ट में चला जाता है, वेयरहाउस के कोने में जाता है, या सबवे सुरंग में। ऐप चलता रहता है, इसलिए वे काम जारी रखते हैं। वे Save दबाते हैं, नोट जोड़ते हैं, स्टेटस बदलते हैं, या नया रिकॉर्ड बनाते हैं। स्क्रीन तुरंत अपडेट होने के कारण सब कुछ ठीक लगता है।

बाद में, कनेक्शन वापस आता है और ऐप बैकग्राउंड में कैच अप करने की कोशिश करता है। यहीं बैकग्राउंड सिंक लोगों को चकित कर सकता है।

अगर ऐप सावधान नहीं है, तो वही एक्शन दो बार भेजा जा सकता है (डुप्लिकेट), या सर्वर का नया चेंज उपयोगकर्ता के अभी किए गए चेंज को ओवरराइट कर सकता है (खोए हुए एडिट)। कभी-कभी ऐप भ्रमित करने वाली अवस्थाएँ दिखाता है जैसे "Saved" और "Not saved" एक साथ, या एक रिकॉर्ड सिंक के बाद दिखाई देता है, गायब हो जाता है, और फिर से दिखाई देता है।

टकराव सरल है: एक ही चीज़ पर दो अलग-अलग परिवर्तन हुए जब तक ऐप उन्हें मेल नहीं कर पाया। उदाहरण के लिए, एक सपोर्ट एजेंट टिकट की प्राथमिकता को "High" कर देता है जबकि वह ऑफ़लाइन है, लेकिन एक टीममेट ऑनलाइन जाकर टिकट को बंद कर देता है। जब ऑफ़लाइन फोन फिर से कनेक्ट होता है, तो दोनों चेंज बिना नियम के साफ़-सुथरे तरीके से लागू नहीं हो सकते।

लक्ष्य ऑफ़लाइन को परिपूर्ण बनाना नहीं है। लक्ष्य इसे पूर्वानुमेय बनाना है:

  • लोग बिना चिंता के काम जारी रख सकें कि उनका काम खो जाएगा।
  • सिंक बाद में हो, बिना रहस्यमय डुप्लिकेट के।
  • जब किसी चीज़ को ध्यान चाहिए, तो ऐप स्पष्ट रूप से बताए कि क्या हुआ और अगला कदम क्या है।

यह बात चाहे आप Kotlin/SwiftUI में हैंड-कोड कर रहे हों या AppMaster जैसे नो-कोड प्लेटफ़ॉर्म से नेटिव ऐप बना रहे हों, दोनों पर लागू होती है। चुनौती UI विजेट्स नहीं है। चुनौती यह तय करना है कि जब उपयोगकर्ता ऑफ़लाइन है तो ऐप का व्यवहार कैसा होगा।

एक सरल ऑफ़लाइन-प्रथम मॉडल (बिना जार्गन के)

एक ऑफ़लाइन-प्रथम ऐप मानता है कि फोन कभी-कभी नेटवर्क खो देगा, लेकिन ऐप को फिर भी उपयोगी महसूस होना चाहिए। स्क्रीन को लोड होना चाहिए और बटन तब भी काम करने चाहिए जब सर्वर उपलब्ध नहीं हो।

चार टर्म्स अधिकतर मामलों को कवर करते हैं:

  • Local cache: डिवाइस पर संग्रहीत डेटा ताकि ऐप तुरंत कुछ दिखा सके।
  • Sync queue: उन क्रियाओं की सूची जो उपयोगकर्ता ने ऑफ़लाइन (या फ्लैक़ी नेटवर्क के दौरान) लीं।
  • Server truth: बैकएंड पर संग्रहीत वह संस्करण जिसे अंततः सभी साझा करते हैं।
  • Conflict: जब उपयोगकर्ता का क्यू में रखा बदलाव अब साफ़ तरीके से लागू नहीं हो पाता क्योंकि सर्वर संस्करण बदल गया।

एक उपयोगी मानसिक मॉडल पढ़ने (reads) और लिखने (writes) को अलग करना है।

Reads आमतौर पर सीधे-सादे होते हैं: सबसे अच्छा उपलब्ध डेटा दिखाएँ (अक्सर लोकल कैश से), फिर नेटवर्क लौटने पर चुपचाप रिफ्रेश करें।

Writes अलग होते हैं। पूरी रिकॉर्ड को एक शॉट में "सहेजने" पर भरोसा मत करें। यह ऑफ़लाइन होते ही टूट जाता है।

इसके बजाय, उपयोगकर्ता ने क्या किया उसे छोटे एंट्रीज़ के रूप में चेंज लॉग में रिकॉर्ड करें। उदाहरण: “status को Approved पर सेट किया”, “कमेंट X जोड़ा”, “quantity 2 से 3 किया।” हर एंट्री को एक टाइमस्टैम्प और ID के साथ सिंक क्यू में डालें। बैकग्राउंड सिंक तब इसे डिलीवर करने की कोशिश करता है।

उपयोगकर्ता काम जारी रखता है जबकि चेंजेज pending से synced होते हैं।

यदि आप AppMaster जैसे नो-कोड प्लेटफ़ॉर्म का उपयोग कर रहे हैं, तो भी आप यही बिल्डिंग ब्लॉक्स चाहेंगे: फास्ट स्क्रीन के लिए कैश्ड रीड्स और उपयोगकर्ता क्रियाओं की एक स्पष्ट क्यू जिसे रीट्राई, मर्ज, या टकराव होने पर फ्लैग किया जा सके।

निर्णय करें कि वास्तव में क्या ऑफ़लाइन सपोर्ट चाहिए

ऑफ़लाइन-प्रथम का मतलब नहीं है "सब कुछ बिना कनेक्शन के काम करता है"—यह वादा कई ऐप्स को मुश्किल में डाल देता है। उन्हीं हिस्सों का चयन करें जो वास्तव में ऑफ़लाइन सपोर्ट से लाभान्वित होते हैं, और बाकी को स्पष्ट रूप से ऑनलाइन-ओनली रखें।

उपयोगकर्ता के इरादे के हिसाब से सोचें: लोग बेसमेंट, फ्लाइट, या वेयरहाउस में किस काम को करना चाहते हैं? एक अच्छा डिफ़ॉल्ट यह है कि रोज़मर्रा के कार्यों को बनाना/अपडेट करना सपोर्ट करें, और वे कार्य ब्लॉक करें जहाँ "नवीनतम सत्य" मायने रखता है।

ऑफ़लाइन-फ्रेंडली एक प्रैक्टिकल सेट में अक्सर कोर रिकॉर्ड्स बनाना और संपादित करना (नोट्स, टास्क, इंस्पेक्शन, टिकट), टिप्पणियाँ ड्राफ्ट करना, और फ़ोटो अटैच करना (स्थानीय रूप से स्टोर, बाद में अपलोड) शामिल होते हैं। डिलीट भी काम कर सकता है, पर यह सुरक्षित है कि इसे सॉफ्ट डिलीट रखें और सर्वर के कन्फर्म होने तक undo विंडो दें।

अब तय करें कि क्या रीयल-टाइम रहना चाहिए क्योंकि जोखिम बहुत ज़्यादा है। पेमेंट्स, परमिशन चेंज, अप्रूवल्स, और संवेदनशील डेटा वाले कार्य आमतौर पर कनेक्शन की मांग करते हैं। अगर सर्वर चेक के बिना उपयोगकर्ता यह सुनिश्चित नहीं कर सकता कि एक्शन वैध है, तो उसे ऑफ़लाइन अनुमति न दें। एक स्पष्ट "कनेक्शन चाहिए" संदेश दिखाएँ, न कि एक रहस्यमय त्रुटि।

ताज़गी के लिए अपेक्षाएँ सेट करें। "ऑफ़लाइन" बाइनरी नहीं है। परिभाषित करें कि डेटा कितना पुराना हो सकता है: मिनट, घंटे, या "अगली बार ऐप खुलने पर"। UI में यह नियम सरल शब्दों में रखें, जैसे "Last updated 2 hours ago" और "Syncing when online"।

अंत में, तेजी से टकराव वाले डेटा को जल्दी फ्लैग करें। इन्वेंटरी काउंट्स, साझा टास्क, और टीम संदेश अक्सर टकराव के केंद्र होते हैं क्योंकि कई लोग तेजी से संपादित करते हैं। इनके लिए विचार करें कि ऑफ़लाइन संपादनों को ड्राफ्ट तक सीमित रखें, या परिवर्तनों को एकल वैल्यू ओवरराइट करने के बजाय अलग-अलग इवेंट्स के रूप में कैप्चर करें।

अगर आप AppMaster में बना रहे हैं, तो यह निर्णय आपको डेटा और बिजनेस नियम मॉडल करने में मदद करेगा ताकि ऐप ऑफ़लाइन सुरक्षित ड्राफ्ट्स स्टोर कर सके जबकि जोखिम वाले क्रियाएँ ऑनलाइन-ओनली रहें।

सिंक क्यू डिज़ाइन: हर बदलाव के लिए आप क्या स्टोर करें

जब उपयोगकर्ता ऑफ़लाइन काम करता है, तो "डेटाबेस को सिंक" करने की कोशिश मत करें। उपयोगकर्ता की क्रियाओं को सिंक करें। एक स्पष्ट एक्शन क्यू बैकग्राउंड सिंक की रीढ़ है, और जब चीज़ें गलत होती हैं तो यह समझने योग्य रहता है।

एक्शन छोटे और मानव-संगत रखें, जो उपयोगकर्ता ने वास्तव में किया था:

  • रिकॉर्ड बनाना
  • विशिष्ट फ़ील्ड(स) अपडेट करना
  • स्टेटस बदलना (submit, approve, archive)
  • डिलीट (सर्वर कन्फर्म होने तक सॉफ्ट डिलीट बेहतर)

छोटी क्रियाएँ डिबग करने में आसान होती हैं। सपोर्ट को मदद करते समय "Changed status Draft -> Submitted" पढ़ना विशाल JSON ब्लॉब की जाँच करने से कहीं आसान है।

हर क्यू किए गए एक्शन के लिए इतना मेटाडेटा रखें कि उसे सुरक्षित रूप से रीप्ले कर सकें और टकराव पता लगा सकें:

  • रिकॉर्ड पहचानकर्ता (और नए रिकॉर्ड्स के लिए एक अस्थायी लोकल ID)
  • एक्शन टाइमस्टैम्प और डिवाइस पहचानकर्ता
  • रिकॉर्ड का एक्सपेक्टेड वर्जन (या आखिरी ज्ञात अपडेट समय)
  • पेलोड (किस फ़ील्ड बदले, साथ में पुराना मान यदि संभव हो)
  • Idempotency key (एक यूनिक एक्शन ID ताकि retries डुप्लिकेट न बनाएं)

यह expected version ईमानदार टकराव हैंडलिंग की कुंजी है। अगर सर्वर वर्जन आगे बढ़ चुका है, तो आप रोक सकते हैं और फैसला करने के लिए पूछ सकते हैं बजाय इसके कि चुपचाप किसी और का डेटा ओवरराइट कर दें।

कुछ क्रियाएँ साथ में लागू होनी चाहिए क्योंकि उपयोगकर्ता उन्हें एक ही स्टेप के रूप में देखता है। उदाहरण: "Create order" और "Add three line items" को एक यूनिट की तरह सफल या असफल होना चाहिए। एक group ID (या transaction ID) रखें ताकि सिंक इंजिन उन्हें साथ भेज सके और या तो सब कमिट हों या सब pending रहें।

चाहे आप हाथ से बनाएं या AppMaster में, लक्ष्य वही है: हर बदलाव एक बार रिकॉर्ड हो, सुरक्षित रूप से रीप्ले हो, और जब कुछ मैच न हो तो समझ में आ सके।

उपयोगकर्ता को समझने योग्य टकराव समाधान नियम

अपना बैकएंड अपनी पसंद से डिप्लॉय करें
अपनी जरूरत के अनुसार ऐप को डिप्लॉय करें—मैनेज्ड क्लाउड से लेकर अपनी इंफ्रास्ट्रक्चर तक।
क्लाउड में लॉन्च करें

टकराव सामान्य हैं। लक्ष्य उन्हें असंभव बनाना नहीं है—लक्ष्य है उन्हें दुर्लभ, सुरक्षित और होने पर समझने में आसान बनाना।

उस क्षण का नाम रखें जब टकराव होता है: ऐप एक बदलाव भेजता है, और सर्वर कहता है, "यह रिकॉर्ड उस वर्जन का नहीं है जिसे आपने एडिट किया था।" इसलिए वर्जनिंग महत्वपूर्ण है।

हर रिकॉर्ड के साथ दो मान रखें:

  • सर्वर वर्जन (सर्वर पर वर्तमान संस्करण)
  • एक्सपेक्टेड वर्जन (जिस वर्जन को फोन ने एडिट किया समझा)

अगर expected version मेल खाता है, तो अपडेट स्वीकार करें और सर्वर वर्जन बढ़ाएँ। अगर नहीं, तो अपना टकराव नियम लागू करें।

हर डेटा प्रकार के लिए एक नियम चुनें (सभी के लिए एक नियम नहीं)

भिन्न डेटा को भिन्न नियम चाहिए। एक स्टेटस फ़ील्ड लंबी नोट जैसी नहीं होती।

उपयोगकर्ताओं को समझ आने वाले नियम:

  • Last write wins: कम जोखिम वाले फ़ील्ड्स के लिए ठीक है, जैसे व्यू प्रेफरेंस।
  • Merge fields: तब सर्वोत्तम जब फ़ील्ड स्वतंत्र हों (status बनाम notes)।
  • उपयोगकर्ता से पूछें: उच्च जोखिम वाले एडिट्स के लिए बेहतर जैसे कि कीमत, परमिशन्स, या टोटल्स।
  • Server wins with a copy: सर्वर मान रखें, लेकिन उपयोगकर्ता का एडिट एक ड्राफ्ट के रूप में सेव करें जिसे वे फिर से लागू कर सकें।

AppMaster में ये नियम विज़ुअल लॉजिक से अच्छी तरह मैच करते हैं: वर्जन चेक करें, फ़ील्ड की तुलना करें, फिर पथ चुनें।

डिलीट कैसे व्यवहार करें यह तय करें (अन्यथा आप डेटा खो देंगे)

डिलीट्स जटिल होते हैं। रिकॉर्ड को तुरंत हटाने के बजाय एक tombstone ("deleted" मार्कर) का उपयोग करें। फिर तय करें कि अगर कहीं और कोई रिकॉर्ड डिलीट कर चुका है तो आपने क्या किया था।

एक स्पष्ट नियम: "Deletes win, पर आप restore कर सकते हैं।" उदाहरण: एक सेल्सपर्सन ऑफ़लाइन ग्राहक नोट एडिट करता है, जबकि एक एडमिन ने वह ग्राहक हटा दिया। जब सिंक चलता है, तो ऐप दिखाए: "Customer was deleted. Restore to apply your note?" यह चुपचाप नुकसान होने से बचाता है और नियंत्रण उपयोगकर्ता के पास रखता है।

पुनःप्रयास और विफलता अवस्थाएँ: इसे पूर्वानुमेय रखें

जब सिंक फेल होता है, अधिकांश उपयोगकर्ता कारण से ज्यादा यह जानना चाहते हैं कि उनका काम सुरक्षित है और आगे क्या होगा। एक पूर्वानुमेय स्टेट मॉडल घबराहट और सपोर्ट टिकट्स कम करता है।

एक छोटा, दिखने योग्य स्टेट मॉडल से शुरू करें और इसे स्क्रीन भर में सुसंगत रखें:

  • Queued: डिवाइस पर सहेजा गया, नेटवर्क के लिए प्रतीक्षा
  • Syncing: अब भेजा जा रहा है
  • Sent: सर्वर द्वारा कन्फर्म किया गया
  • Failed: भेजा नहीं जा सका, फिर से प्रयास होगा या ध्यान चाहिए
  • Needs review: भेजा गया, पर सर्वर ने ठुकराया या फ्लैग किया

रीट्राई बैटरी और डेटा पर नरम होने चाहिए। पहले तेज़ रीट्राई करें (छोटे सिग्नल ड्राप्स के लिए), फिर धीरे-धीरे धीमा करें। एक साधारण बैकऑफ़ जैसे 1 मिनट, 5 मिनट, 15 मिनट, फिर हर घंटे आसान है। साथ ही केवल सही परिस्थितियों में रीट्राई करें (एक अमान्य बदलाव को हर बार रीट्राई न करें)।

त्रुटियों को अलग तरह से संभालें, क्योंकि अगला कदम अलग होगा:

  • Offline / no network: क्यू में रहे, ऑनलाइन होने पर रीट्राई
  • Timeout / server unavailable: फेल मार्क करें, बैकऑफ़ के साथ ऑटो-रीट्राई
  • Auth expired: सिंक को रोकें और उपयोगकर्ता से पुनः साइन-इन माँगें
  • Validation failed (बुरा इनपुट): needs review, दिखाएँ क्या ठीक करना है
  • Conflict (रिकॉर्ड बदल गया): needs review, अपने टकराव नियमों पर रूट करें

Idempotency वह चीज़ है जो रीट्राई को सुरक्षित रखती है। हर बदलाव में एक यूनिक एक्शन ID (अक्सर UUID) होना चाहिए जिसे रिक्वेस्ट के साथ भेजा जाए। अगर ऐप वही बदलाव फिर से भेजता है, तो सर्वर को उस ID को पहचानकर वही परिणाम वापस करना चाहिए बजाय इसके कि डुप्लिकेट बन जाएँ।

उदाहरण: एक तकनीशियन ऑफ़लाइन एक पूरा हुआ जॉब सेव करता है, फिर लिफ्ट में चला जाता है। ऐप अपडेट भेजता है, टाइमआउट हो जाता है, और बाद में रीट्राई करता है। एक्शन ID होने पर दूसरा भेजना हानिरहित होगा। बिना इसके आप डुप्लिकेट "completed" इवेंट बना सकते हैं।

AppMaster में इन स्टेट्स और नियमों को अपने सिंक प्रोसेस में पहला दर्जा बनाएं, ताकि आपके Kotlin और SwiftUI ऐप्स हर जगह एक जैसा व्यवहार करें।

पेंडिंग चेंजेज UX: उपयोगकर्ता क्या देखता है और क्या कर सकता है

टकराव को पूर्वानुमेय बनाएँ
संस्करण जांच और टकराव नियमों को स्पष्ट, परखने योग्य बिजनेस प्रोसेस के रूप में जोड़ें।
अब बनाएं

लोगों को ऑफ़लाइन ऐप इस्तेमाल करते समय सुरक्षित महसूस होना चाहिए। अच्छा "pending changes" UX शांत और पूर्वानुमेय होता है: यह स्वीकार करता है कि काम डिवाइस पर सहेजा गया है, और अगला कदम स्पष्ट करता है।

एक सूक्ष्म संकेत एक चेतावनी बैनर से बेहतर काम करता है। उदाहरण के लिए, हेडर में एक छोटा "Syncing" आइकन दिखाएँ, या edits वाले स्क्रीन पर एक शांत "3 pending" लेबल। असली खतरे के लिए डरावने रंग रखें (जैसे "अपलोड नहीं कर सकता क्योंकि आप साइन आउट हैं")।

उपयोगकर्ताओं को समझने के लिए एक स्थान दें। एक सरल Outbox या Pending changes स्क्रीन आइटम्स की सूची कर सकती है जैसे "Comment added to Ticket 104" या "Profile photo updated." यह पारदर्शिता घबराहट रोकती है और सपोर्ट टिकट्स घटाती है।

उपयोगकर्ता क्या कर सकते हैं

अधिकांश लोगों को कुछ ही क्रियाएँ चाहिए, और वे पूरे ऐप में सुसंगत होनी चाहिए:

  • अभी retry करें
  • फिर से एडिट करें (नया बदलाव बनेगा)
  • लोकल बदलाव discard करें
  • विवरण कॉपी करें (इश्यू रिपोर्ट करते समय उपयोगी)

स्टेट लेबल सरल रखें: Pending, Syncing, Failed। जब कुछ फेल हो, तो इसे मानवीय भाषा में समझाएँ: "Upload नहीं हो सका। इंटरनेट नहीं है।" या "अस्वीकृत: इस रिकॉर्ड को किसी और ने बदल दिया।" एरर कोड्स से बचें।

पूरे ऐप को ब्लॉक मत करें

सिर्फ़ उन्हीं क्रियाओं को ब्लॉक करें जिन्हें वास्तव में ऑनलाइन होना अनिवार्य है, जैसे "Stripe के साथ पे करें" या "नया उपयोगकर्ता invite करें।" बाकी सब कुछ काम करना चाहिए, जिसमें हाल का डेटा देखना और नए ड्राफ्ट बनाना भी शामिल है।

एक वास्तविक प्रवाह: एक फ़ील्ड टेक बेसमेंट में एक जॉब रिपोर्ट एडिट करता है। ऐप "1 pending" दिखाता है और उसे काम जारी रखने देता है। बाद में यह "Syncing" में बदलता है, फिर अपने आप साफ़ हो जाता है। अगर यह फेल हो जाता है, तो जॉब रिपोर्ट उपलब्ध रहती है, "Failed" के रूप में चिन्हित, और एक सिंगल "Retry now" बटन होता है।

यदि आप AppMaster में बना रहे हैं, तो इन स्टेट्स को प्रत्येक रिकॉर्ड का हिस्सा मॉडल करें (pending, failed, synced) ताकि UI हर जगह बिना स्पेशल-केस स्क्रीन के इन्हें दिखा सके।

ऑथ, परमिशन्स, और ऑफ़लाइन में सुरक्षा

ऑफ़लाइन काम के लिए डेटा मॉडल करें
PostgreSQL-फर्स्ट शैली में अपना डेटा मॉडल डिजाइन करें और ऑफ़लाइन ड्राफ्ट्स को सुसंगत रखें।
प्रोजेक्ट शुरू करें

ऑफलाइन मोड आपके सुरक्षा मॉडल को बदल देता है। उपयोगकर्ता बिना कनेक्शन के क्रियाएँ कर सकता है, पर आपका सर्वर फिर भी सत्य का स्रोत है। हर क्यू किया गया बदलाव "अनुरोधित" माना जाना चाहिए, न कि "स्वीकृत"।

ऑफ़लाइन के दौरान लॉगिन की समय-सीमा

टोकन की एक्स्पायरी होती है। जब यह ऑफ़लाइन होते हुए एक्स्पायर हो जाए, तो उपयोगकर्ता को एडिट्स बनाते रहने दें और उन्हें pending के रूप में स्टोर करें। उन क्रियाओं को जो सर्वर कन्फर्मेशन चाहिए वे पूरी नहीं मानी जानी चाहिए। अगले सफल ऑथ रिफ्रेश तक उन्हें pending के रूप में रखें।

ऐप ऑनलाइन आने पर पहले साइलेंट रिफ्रेश करने की कोशिश करें। अगर उपयोगकर्ता को फिर साइन-इन करना पड़े, तो एक बार पूछें और फिर सिंक अपने आप जारी रखें।

रि-लॉगिन के बाद, हर क्यू आइटम को भेजने से पहले री-वैधेट करें। उपयोगकर्ता पहचान बदल चुकी हो सकती है (शेयर्ड डिवाइस), और पुराने एडिट्स गलत अकाउंट के तहत सिंक नहीं होने चाहिए।

परमिशन बदलाव और निषिद्ध क्रियाएँ

ऑनलाइन रहते हुए परमिशन्स बदल सकती हैं। वह एडिट जो कल अनुमति था, आज निषिद्ध हो सकता है। इसे स्पष्ट रूप से हैंडल करें:

  • हर क्यू आइटम के लिए सर्वर-साइड परमिशन फिर से चेक करें
  • अगर निषिद्ध है, तो उस आइटम को रोकें और स्पष्ट कारण दिखाएँ
  • उपयोगकर्ता का लोकल एडिट रखें ताकि वे उसे कॉपी कर सकें या एक्सेस का अनुरोध कर सकें
  • "Forbidden" त्रुटियों के लिए बार-बार रीट्राई से बचें

उदाहरण: एक सपोर्ट एजेंट फ्लाइट में ऑफ़लाइन ग्राहक नोट एडिट करता है। रातभर में उसकी भूमिका हटा दी जाती है। जब सिंक चलता है, सर्वर अपडेट ठुकरा देता है। ऐप दिखाना चाहिए: "Upload नहीं हो सका: आपके पास अब एक्सेस नहीं है" और नोट को लोकल ड्राफ्ट के रूप में रखें।

संवेदनशील डेटा का ऑफ़लाइन स्टोरेज

स्क्रीन्स रेंडर करने और क्यू रीप्ले करने के लिए न्यूनतम ही स्टोर करें। ऑफ़लाइन स्टोरेज को एन्क्रिप्ट करें, सीक्रेट्स कैश न करें, और लॉगआउट के नियम स्पष्ट रखें (उदाहरण: लोकल डेटा वाइप करें, या केवल उपयोगकर्ता की स्पष्ट सहमति पर ड्राफ्ट रखें)। AppMaster से बनाते समय उसके ऑथ मॉड्यूल से शुरुआत करें और अपनी क्यू इस तरह डिजाइन करें कि यह हमेशा वैध सेशन के लिए प्रतीक्षा करे फिर ही चेंज भेजे।

सामान्य जाल जिनसे काम खो जाता है या रिकॉर्ड डुप्लिकेट होते हैं

अधिकांश ऑफ़लाइन बग्स जटिल नहीं होते। वे कुछ छोटे फैसलों से आते हैं जो परफेक्ट वाई-फाई पर टेस्ट करते समय हानिरहित लगते हैं, पर असली दुनिया में टूट जाते हैं।

एक सामान्य विफलता है साइलेंट ओवरराइट्स। अगर ऐप पुराने वर्जन को अपलोड कर देता है और सर्वर बिना जांचे उसे स्वीकार कर लेता है, तो आप किसी और के नए एडिट को मिटा सकते हैं और कोई नोटिस नहीं करेगा जब तक बहुत देर न हो जाए। वर्जन नंबर (या "last updated" स्टैम्प) के साथ सिंक करें और जब सर्वर आगे बढ़ चुका हो तो ओवरराइट करने से इंकार करें, ताकि उपयोगकर्ता को स्पष्ट विकल्प मिले।

एक और जाल है retry storm। जब फोन कमजोर कनेक्शन मिलने पर फिर से कनेक्ट होता है, तो ऐप हर कुछ सेकंड में बैकएंड पर हमला कर सकता है, बैटरी खत्म कर सकता है और डुप्लिकेट राइट्स बना सकता है। रीट्राई शांत होने चाहिए: हर विफलता के बाद धीमे हों और थोड़ा randomness जोड़ें ताकि हजारों डिवाइस एक ही समय में रीट्राई न करें।

सबसे सामान्य गलतियाँ जो काम खोने या डुप्लिकेट्स की ओर ले जाती हैं:

  • हर फेल्योर को "नेटवर्क" जैसा मानना: स्थायी त्रुटियों (अमान्य डेटा, अनुमति नहीं) को अस्थायी (टाइमआउट) से अलग करें।
  • सिंक विफलताओं को छिपाना: अगर लोग नहीं देख पाते क्या फेल हुआ, तो वे काम को दोहराते हैं और दो रिकॉर्ड बन जाते हैं।
  • एक ही बदलाव दो बार भेजना बिना सुरक्षा के: हमेशा एक यूनिक रिक्वेस्ट ID भेजें ताकि सर्वर डुप्लिकेट को पहचान सके।
  • टेक्स्ट फ़ील्ड्स को ऑटो-मार्ज करना बिना किसी को बताए: अगर आप ऑटो-मार्ज करते हैं, तो उपयोगकर्ताओं को परिणाम की जाँच करने का मौका दें जब यह मायने रखता है।
  • ऑफ़लाइन रिकॉर्ड बनाना बिना स्थिर ID के: एक अस्थायी लोकल ID का उपयोग करें और अपलोड के बाद उसे सर्वर ID से मैप करें, ताकि बाद के एडिट्स दूसरा रिकॉर्ड न बना दें।

एक शीघ्र उदाहरण: एक फ़ील्ड टेक एक नया "Site Visit" ऑफ़लाइन बनाता है, फिर उसे दो बार एडिट करता है फिर कनेक्ट होता है। अगर create कॉल रीट्राई करते हुए दो सर्वर रिकॉर्ड बना देती है, तो बाद के एडिट्स गलत रिकॉर्ड से जुड़ सकते हैं। स्थिर IDs और सर्वर-साइड डेडुपिंग इसे रोकते हैं।

यदि आप AppMaster के साथ बना रहे हैं, नियम वही रहते हैं—फर्क केवल यह है कि आप उन्हें कहाँ लागू करते हैं: अपने सिंक लॉजिक, डेटा मॉडल, और उन स्क्रीन में जो "failed" बनाम "sent" चेंज दिखाती हैं।

उदाहरण परिदृश्य: दो लोग एक ही रिकॉर्ड एडिट करते हैं

दोबारा लिखे बिना नेटिव जाएँ
एक सोर्स ऑफ ट्रूथ रखते हुए नेटिव Kotlin और SwiftUI आउटपुट उपयोग करें।
शुरू करें

एक फ़ील्ड टेक्नीशियन, Maya, "Job #1842" टिकट को बेसमेंट में अपडेट कर रही है बिना सिग्नल के। वह स्टेटस को "In progress" से "Completed" कर देती है और नोट जोड़ती है: "Replaced valve, tested OK." ऐप तुरंत सेव कर देता है और इसे pending दिखाता है।

ऊपर, उसकी टीममेट Leo ऑनलाइन है और उसी समय वही जॉब एडिट कर रहा है। वह शेड्यूल समय बदलता है और जॉब एक दूसरे टेक्नीशियन को असाइन कर देता है क्योंकि ग्राहक ने अपडेट दिया।

जब Maya सिग्नल पाती है, बैकग्राउंड सिंक चुपचाप शुरू होता है। एक पूर्वानुमेय, उपयोगकर्ता-मित्र प्रवाह में यह होता है:

  1. Maya का बदलाव अभी भी सिंक क्यू में है (job ID, बदले गए फ़ील्ड, टाइमस्टैम्प, और रिकॉर्ड का वर्जन जो उसने आख़िरी बार देखा था)।
  2. ऐप अपलोड करने की कोशिश करता है। सर्वर जवाब देता है: "यह जॉब आपके वर्जन से अपडेट किया गया है" (एक टकराव)।
  3. आपका टकराव नियम चलता है: स्टेटस और नोट्स मर्ज हो सकते हैं, पर असाइनमेंट सर्वर पर बाद में किए गए परिवर्तन को जीतने दें।
  4. सर्वर एक मर्ज्ड परिणाम स्वीकार करता है: status = "Completed" (Maya से), नोट जोड़ा गया (Maya से), assigned technician = Leo का विकल्प (Leo से)।
  5. Maya के ऐप में जॉब फिर खुलता है एक स्पष्ट बैनर के साथ: "Synced with updates. Assignment changed while you were offline." एक छोटा "Review" एक्शन दिखाता है कि क्या बदला।

अब एक फ़ेल्योर जोड़ें: Maya का लॉगिन टोकन ऑफ़लाइन रहते हुए एक्स्पायर हो गया। पहली सिंक कोशिश "Sign in required" से फेल होती है। ऐप उसके एडिट्स को रखता है, उन्हें "Paused" के रूप में मार्क करता है, और एक सिंगल सरल प्रॉम्प्ट दिखाता है। जब वह साइन इन करती है, तो सिंक बिना कुछ फिर से टाइप कराए अपने आप दोबारा शुरू हो जाता है।

यदि वहाँ कोई वैलिडेशन समस्या है (उदाहरण: "Completed" के लिए फोटो अनिवार्य है), तो ऐप अनुमान न लगाए। वह आइटम को "Needs attention" के रूप में चिह्नित करे, ठीक वही बताए जो जोड़ना है, और फिर फिर से सबमिट करने दे।

AppMaster जैसे प्लेटफ़ॉर्म यहाँ मदद करते हैं क्योंकि आप क्यू, टकराव नियम, और pending-state UX को विज़ुअली डिजाइन कर सकते हैं, जबकि असली नेटिव Kotlin और SwiftUI ऐप्स भेजते हैं।

त्वरित चेकलिस्ट और आगे के कदम

ऑफ़लाइन सिंक को एक end-to-end फीचर मानें जिसे आप टेस्ट कर सकते हैं, न कि फिक्सेस का एक ढेर। लक्ष्य सरल है: उपयोगकर्ता कभी यह न सोचें कि उनका काम सेव हुआ या नहीं, और ऐप आश्चर्यजनक डुप्लिकेट न बनाए।

एक छोटी चेकलिस्ट ताकि नींव ठोस हो:

  • सिंक क्यू डिवाइस पर स्टोर हो, और हर बदलाव का एक स्थिर लोकल ID हो साथ में सर्वर ID जब उपलब्ध हो।
  • स्पष्ट स्टेट्स मौजूद हों (queued, syncing, sent, failed, needs review) और सुसंगत रूप से इस्तेमाल हों।
  • रिक्वेस्ट्स idempotent हों (रीट्राई के लिए सुरक्षित), और हर ऑपरेशन में idempotency key हो।
  • रिकॉर्ड्स में वर्जनिंग हो (updatedAt, revision number, या ETag) ताकि टकराव पता चल सके।
  • टकराव नियम सरल भाषा में लिखे हों (क्या जीतता है, क्या मर्ज होता है, कब उपयोगकर्ता से पूछा जाता है)।

एक बार ये जगह पर हों, अनुभव की जाँच करें कि यह डेटा मॉडल जितना मजबूत है उतना ही मजबूत है। उपयोगकर्ता यह देख सकें कि क्या pending है, क्या फेल हुआ, और बिना काम खोए क्या कर सकते हैं।

वास्तविक जीवन से मिलते-जुलते परिदृश्यों से टेस्ट करें:

  • एयरप्लेन मोड एडिट्स: बनाएं, अपडेट करें, डिलीट करें, फिर रीकनेक्ट करें।
  • फ्लैक़ी नेटवर्क: सिंक के बीच कनेक्शन ड्रॉप करें और सुनिश्चित करें कि रीट्राई डुप्लिकेट न बनाएं।
  • ऐप बंद हो गया: भेजते समय फ्रोर्स क्लोज़ करें, फिर खोलें और पुष्टि करें कि क्यू रिकवर कर रहा है।
  • क्लॉक स्क्यू: डिवाइस समय गलत हो, पुष्टि करें कि टकराव डिटेक्शन अभी भी काम करता है।
  • डुप्लिकेट टैप: उपयोगकर्ता Save दो बार दबाता है, पुष्टि करें कि यह एक सर्वर परिवर्तन बनता है।

UI पोलिश करने से पहले पूरे फ्लो का प्रोटोटाइप बनाएं। एक स्क्रीन, एक रिकॉर्ड टाइप, और एक टकराव केस (एक ही फ़ील्ड पर दो एडिट) बनाकर शुरू करें। एक सरल सिंक स्टेट एरिया, विफलताओं के लिए Retry बटन, और एक स्पष्ट टकराव स्क्रीन जोड़ें। जब वह काम करे, तो और स्क्रीन के लिए इसे दोहराएँ।

अगर आप बिना कोडिंग के बना रहे हैं, AppMaster (appmaster.io) एक ही परियोजना से नेटिव Kotlin और SwiftUI ऐप्स के साथ बैकएंड जनरेट कर सकता है, ताकि आप क्यू, वर्जन चेक, और उपयोगकर्ता-समक्ष अवस्थाओं पर ध्यान केंद्रित कर सकें बजाय सब कुछ हाथ से जोड़ने के।

शुरू करना आसान
कुछ बनाएं अद्भुत

फ्री प्लान के साथ ऐपमास्टर के साथ प्रयोग करें।
जब आप तैयार होंगे तब आप उचित सदस्यता चुन सकते हैं।

शुरू हो जाओ