सभी लेख
Deep diveपढ़ने में 8 मिनट

Apple और Google दोनों वही रिफंड आपके सर्वर पर एक से अधिक बार पहुँचा सकते हैं, और डुप्लिकेट रिफंड सूचनाएँ आपको महँगी पड़ती हैं यदि आप हर एक पर कार्रवाई करते हैं

Apple एक रिफंड सूचना को पाँच बार तक दोबारा भेजता है और Google Play, Pub/Sub पर कम-से-कम-एक-बार चलता है, इसलिए वही रिफंड आपके सर्वर पर एक से अधिक बार पहुँच सकता है। यहाँ बताया गया है कि किसी बैलेंस को घटाए या API कोटा दो बार जलाए बिना डुप्लिकेट रिफंड सूचनाओं को कैसे संभालें।

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

मुख्य बातें

  • Apple एक App Store Server Notification V2 को पाँच बार दोबारा भेजता है, पिछले प्रयास के 1, 12, 24, 48, और 72 घंटे बाद, जब भी आपका सर्वर 200 और 206 के बीच के किसी HTTP status के साथ जवाब नहीं देता। पहले प्रयास को गिनें तो एक ही रिफंड छह बार तक पहुँच सकता है।
  • हर असली Apple रिट्राई वही notificationUUID लेकर आती है, इसलिए वही फ़ील्ड, न कि transaction id, आपकी डीडुप्लिकेशन कुंजी है।
  • Google Play की Real-time Developer Notifications, Cloud Pub/Sub पर चलती हैं, जो कम-से-कम-एक-बार डिलीवरी की गारंटी देती है और कोई क्रम नहीं, इसलिए वही संदेश दो बार या क्रम से बाहर आ सकता है। Google आपको कहता है कि कुछ भी प्रोसेस करने से पहले विशिष्टता के लिए messageId जाँच लें।
  • Apple की समय-समय पर आने वाली CONSUMPTION_REQUEST सूचनाएँ रिट्राई नहीं हैं। Apple खुली रिफंड विंडो के दौरान नई सूचनाएँ भेजता रहता है, हर एक का अलग notificationUUID होता है, इसलिए notificationUUID पर डीडुप्लिकेट करने से उनमें से हर एक सही ढंग से बनी रहती है।
  • वही Apple transactionId एक से अधिक निर्णय ले जा सकता है, उदाहरण के लिए एक REFUND_DECLINED और बाद में एक REFUND, इसलिए केवल transaction id पर डीडुप्लिकेट करने से एक अलग घटना फेंक दी जाती है जिसकी आपको ज़रूरत थी।
  • किसी डुप्लिकेट को 4xx या 5xx लौटाकर अस्वीकार करना केवल स्टोर से उसे दोबारा भिजवाता है। अपने ही डेटाबेस के भीतर डीडुप्लिकेट करें और हमेशा एक सफलता status लौटाएँ।
  • एक रिफंड हैंडलर जो idempotent नहीं है, दूसरी डिलीवरी पर दोहरी कार्रवाई करता है। यह किसी बैलेंस को दो बार घटाता है, किसी पेआउट को दो बार उलटता है, या पहले से बंद किए गए रिफंड को दोबारा जाँचते हुए बिल-योग्य Play Developer और App Store Server API कोटा जलाता है।

आपका सर्वर वही रिफंड इवेंट एक से अधिक बार प्राप्त करेगा, और दोनों स्टोर ने इसे जानबूझकर इसी तरह डिज़ाइन किया है। जब आपका एंडपॉइंट साफ़ जवाब नहीं देता तो Apple एक App Store Server Notification को पाँच बार तक दोबारा भेजता है। Google Play अपनी Real-time Developer Notifications को Cloud Pub/Sub पर पहुँचाता है, जो कम-से-कम-एक-बार डिलीवरी का वादा करती है और क्रम के बारे में कुछ नहीं। तो सवाल कभी यह नहीं होता कि डुप्लिकेट आता है या नहीं। सवाल यह है कि वही रिफंड दूसरी बार देखने पर आपका कोड क्या करता है। इसे ग़लत करें और आप किसी बैलेंस को दो बार घटा देते हैं, किसी पेआउट को दो बार उलट देते हैं, या पहले से बंद किए गए रिफंड को दोबारा जाँचते हुए बिल-योग्य API कोटा जला देते हैं। यहाँ बताया गया है कि डुप्लिकेट रिफंड सूचनाएँ असल में आप तक कैसे पहुँचती हैं, कौन से दोहराव असली डुप्लिकेट हैं और कौन से केवल वैसे दिखते हैं, और उन्हें कैसे संभालें ताकि दूसरी डिलीवरी मुफ़्त रहे।

एक रिफंड सूचना कम-से-कम एक बार पहुँचाई जाती है, जो ठीक-एक-बार जैसी नहीं है

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

Apple तीन दिनों में पाँच बार दोबारा भेजता है

जब Apple एक App Store Server Notification V2 भेजता है, तो वह आपके सर्वर से 200 से 206 की सीमा में एक HTTP status के साथ जवाब की अपेक्षा करता है। इसके अलावा कुछ भी, कोई 4xx या 5xx, Apple को बताता है कि डिलीवरी विफल हुई, और Apple दोबारा भेजता है। अनुसूची तय है: पाँच रिट्राई, पिछले प्रयास के 1, 12, 24, 48, और 72 घंटे बाद। पहले प्रयास को गिनें तो एक रिफंड इवेंट छह बार तक पहुँच सकता है, लगभग एक हफ़्ते में फैला हुआ। इनमें से हर रिट्राई वही notificationUUID लेकर आती है। वह फ़ील्ड आपकी डीडुप्लिकेशन कुंजी है। यदि आपने पहले ही कोई notificationUUID रिकॉर्ड कर रखा है, तो आपके पास जो डिलीवरी है वह एक दोहराव है, और सही प्रतिक्रिया यह है कि कुछ नया संग्रहित न करें और फिर भी 200 लौटाएँ।

Google Play, Pub/Sub पर चलता है, जो कम-से-कम एक बार का वादा करता है और क्रम के बारे में कुछ नहीं कहता

Google Play की Real-time Developer Notifications एक Cloud Pub/Sub टॉपिक पर प्रकाशित होती हैं। Pub/Sub की डिलीवरी गारंटी कम-से-कम-एक-बार है, और यह क्रम की कोई गारंटी बिल्कुल नहीं देती। इसका मतलब है कि वही संदेश आपके एंडपॉइंट पर एक से अधिक बार पहुँचाया जा सकता है, और एक ही खरीद के दो संदेश क्रम से बाहर आ सकते हैं। Google का अपना मार्गदर्शन स्पष्ट है: base64 data फ़ील्ड को खोलें, messageId पढ़ें, और कुछ भी प्रोसेस करने से पहले जाँचें कि आपने उसे पहले नहीं देखा है। एक डुप्लिकेट messageId एक दोहराव है जिसे आप छोड़ देते हैं। एक ही खरीद के बारे में दो अलग सूचनाओं को फिर भी उसी रिकॉर्ड पर उतरना चाहिए, इसलिए अपनी संग्रहित स्थिति को purchaseToken पर भी कुंजीबद्ध करें, और किसी बाद के इवेंट को उस पंक्ति को अपडेट करने दें जिसे पहले वाले ने बनाया था।

प्लेटफ़ॉर्मडिलीवरी मॉडलकिस पर डीडुप्लिकेट करेंसफलता संकेतयदि आप स्वीकृति नहीं देते
App Store Server Notifications V26 प्रयासों तक: पहला, और 1, 12, 24, 48, 72 घंटे पर 5 रिट्राईnotificationUUIDHTTP 200 से 206Apple तय अनुसूची पर दोबारा भेजता है, फिर रुक जाता है
Google Play RTDN, Pub/Sub परकम-से-कम-एक-बार, क्रम की कोई गारंटी नहींPub/Sub messageId, purchaseToken पर एंटिटी-कुंजीबद्धपुश पर HTTP 200, या एक स्पष्ट ackack समयसीमा समाप्त होने के बाद Pub/Sub दोबारा भेजता है

वे दोहराव जो डुप्लिकेट नहीं हैं

हर सूचना जो आपकी देखी हुई किसी सूचना जैसी दिखती है, रिट्राई नहीं होती। दो Apple व्यवहार सचमुच नई घटनाएँ भेजते हैं जो एक खरीद साझा करती हैं लेकिन हर एक को प्रोसेस किया जाना चाहिए, और उन्हें एक भोले-भाले डीडुप्लिकेशन से समेट देना उस जानकारी को फेंक देता है जिसकी आपको ज़रूरत थी।

Apple नए CONSUMPTION_REQUEST भेजता है, रिट्राई नहीं

किसी उपभोग्य पर खुले रिफंड अनुरोध के दौरान, Apple एक CONSUMPTION_REQUEST भेजकर इंतज़ार नहीं करता। वह पूरी खुली रिफंड विंडो में समय-समय पर नए भेजता है, जब तक रिफंड बंद नहीं हो जाता। Apple के स्टाफ़ ने पुष्टि की है कि ये रिट्राई नहीं हैं, और पहचान वही फ़ील्ड है जिस पर आप डीडुप्लिकेट करते हैं: हर नया CONSUMPTION_REQUEST एक अलग notificationUUID लेकर आता है। इसलिए notificationUUID पर कुंजीबद्ध डीडुप्लिकेशन अपने आप सही काम करता है। यह असली रिट्राई को समेट देता है और हर अलग प्रॉम्प्ट को बनाए रखता है। जो आपको नहीं करना चाहिए वह है transaction id और सूचना प्रकार पर डीडुप्लिकेट करना, क्योंकि इससे पहले वाले के बाद हर CONSUMPTION_REQUEST खामोश हो जाएगा और आप जिन्हें गिरा देते हैं उन पर 12-घंटे की साक्ष्य विंडो गँवा देंगे।

एक लेनदेन एक से अधिक निर्णय ले जा सकता है

एक ही transactionId अपने जीवन में एक से अधिक रिफंड परिणाम उत्पन्न कर सकता है। Apple एक REFUND_DECLINED भेज सकता है और फिर बाद में उसी लेनदेन के लिए एक REFUND, और डेवलपर एक ही transaction id के लिए तीन या अधिक रिफंड-संबंधी सूचनाएँ प्राप्त करने की रिपोर्ट करते हैं। हर एक अपने स्वयं के notificationUUID के साथ एक अलग इवेंट है। यदि आपकी डीडुप्लिकेशन कुंजी transaction id है, तो दूसरा निर्णय पहले के डुप्लिकेट जैसा दिखता है और आपको कभी पता नहीं चलता कि रिफंड आख़िरकार मंज़ूर हुआ था। transaction id घटनाओं को समूहित करता है। यह उन्हें पहचानता नहीं है।

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

एक डुप्लिकेट असल में आपको क्या खर्च कराता है

एक रिफंड सूचना कोई स्थिति-रोशनी नहीं है। यह असली कार्रवाइयाँ चालू करती है: आप पहुँच रद्द करते हैं, आप एक उपभोग्य बैलेंस घटाते हैं, आप एक क्रिएटर पेआउट उलटते हैं, आप स्थिति की पुष्टि के लिए App Store Server API या Play Developer API कॉल करते हैं। इनमें से किसी को भी किसी डुप्लिकेट पर दूसरी बार चलाएँ और लागत असली है।

पैसे का हिसाब लगाएँ। पहुँच को दो बार रद्द करना हानिरहित है, क्योंकि पहुँच पहले ही चली गई है। बैलेंस को दो बार घटाना ऐसा नहीं है: एक उपयोगकर्ता जिसने सिक्कों का एक पैक ख़रीदा और उसे रिफंड कराया, उसे एक नकारात्मक बैलेंस तक धकेला जा सकता है जिसे फिर आपकी सपोर्ट टीम को हाथ से सुलझाना पड़ता है। किसी पेआउट को दो बार उलटना उस पैसे को वापस खींच लेता है जो आप पहले ही एक बार लौटा चुके थे, और अब आप एक क्रिएटर के प्रति माफ़ी और सुधार के कर्ज़दार हैं। और हर डुप्लिकेट जिसे आप किसी स्टोर API के विरुद्ध दोबारा प्रोसेस करते हैं वह उस कोटे को खर्च करता है जिसकी रक्षा करने की Google स्पष्ट रूप से चेतावनी देता है, इसलिए किसी आउटेज के दौरान Pub/Sub पुनर्वितरण का एक झोंका आपको ठीक उसी दिन रेट लिमिटिंग में धकेल सकता है जिस दिन आप इसे सबसे कम झेल सकते हैं।

Apple की ओर से रिफंड साक्ष्य विंडो दाँव को बढ़ा देती हैं। यदि एक भोला-भाला डीडुप्लिकेशन उन दोहराई गई CONSUMPTION_REQUEST को खामोश कर देता है जो Apple खुली रिफंड विंडो में भेजता है, तो आप उसी को चूक सकते हैं जिसका आपको जवाब देना था, और एक CONSUMPTION_REQUEST जिसका आप 12 घंटे के भीतर जवाब नहीं देते वह एक ऐसा रिफंड है जिसे Apple अक्सर डिफ़ॉल्ट रूप से मंज़ूर कर देता है। यह दोहरा-शुल्क नहीं है। यह एक खोई हुई बिक्री है, साथ ही वह कंप्यूट, API कॉल, स्टोरेज, और पेआउट जो आप खरीद पहुँचाने में पहले ही खर्च कर चुके थे, जिनमें से कुछ भी रिफंड वापस नहीं करता।

विफलता का तरीकाक्या ग़लत होता हैइसकी लागत क्या है
किसी डुप्लिकेट REFUND पर बैलेंस दोबारा घटानाउपयोगकर्ता का उपभोग्य बैलेंस नकारात्मक हो जाता हैमिलान के लिए मैन्युअल सपोर्ट समय, और एक ख़राब ग्राहक अनुभव
किसी पेआउट को दो बार उलटनाआप उस पैसे को वापस खींच लेते हैं जो आप पहले ही एक बार लौटा चुके थेएक क्रिएटर सुधार और एक लेखांकन सफ़ाई
किसी स्टोर API के विरुद्ध दोबारा प्रोसेस करनाडुप्लिकेट कॉल Play Developer या App Store Server API कोटा जलाती हैंउस आउटेज के दौरान रेट लिमिटिंग जिसने पुनर्वितरण पैदा किया
CONSUMPTION_REQUEST पर अति-डीडुप्लिकेशनआप एक अलग रिफंड प्रॉम्प्ट को झूठे डुप्लिकेट के रूप में गिरा देते हैंएक छूटी हुई 12-घंटे की विंडो, इसलिए Apple डिफ़ॉल्ट रूप से रिफंड मंज़ूर कर देता है

दोहरी कार्रवाई किए बिना डुप्लिकेट रिफंड सूचनाओं को कैसे संभालें

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

  • स्टोर की डिलीवरी id पर डीडुप्लिकेट करें, लेनदेन पर नहीं। Apple के लिए notificationUUID और Google Play के लिए Pub/Sub messageId का उपयोग करें। इसे एक यूनीक कंस्ट्रेंट के साथ संग्रहित करें ताकि एक समवर्ती डुप्लिकेट दोहरी कार्रवाई करने के बजाय दौड़ हार जाए।
  • डाउनस्ट्रीम कार्रवाई को अपनी शर्तों पर idempotent बनाएँ। डिलीवरी id पर कुंजीबद्ध करना पुनर्प्रसंस्करण को रोकता है, लेकिन प्रभाव को भी ऐसे लिखें कि रद्द करना, घटाना, या उलटना पहले वर्तमान स्थिति जाँचे और दो बार चलाना सुरक्षित हो।
  • पहले सहेजें, फिर स्वीकृति दें। 200 लौटाने या Pub/Sub संदेश को ack करने से पहले इवेंट को अपने डेटाबेस में लिखें। यदि आप पहले ack करते हैं और लिखना विफल हो जाता है, तो स्टोर संदेश को पहुँचाया गया मानता है और उसे फिर कभी नहीं भेजता, और अब आपने उसे हमेशा के लिए खो दिया है।
  • हमेशा एक सफलता status लौटाएँ, यहाँ तक कि किसी डुप्लिकेट के लिए भी। Apple के लिए 200 से 206, Google के लिए Pub/Sub पुश पर 200। किसी दोहराव को एरर के साथ अस्वीकार करना केवल स्टोर से उसे दोबारा भिजवाता है।
  • एंटिटी पर समूहित करें, इवेंट पर पहचानें। अपनी संग्रहित खरीद स्थिति को purchaseToken या originalTransactionId पर कुंजीबद्ध करें ताकि क्रम-से-बाहर डिलीवरी एक ही पंक्ति को अपडेट करें, लेकिन हर notificationUUID या messageId को उसकी अपनी घटना के रूप में मानें, क्योंकि एक खरीद वैध रूप से कई उत्पन्न करती है।

अपने रिफंड webhook पर भरोसा करने से पहले एक छोटी चेकलिस्ट

  • Apple डिलीवरी notificationUUID पर डीडुप्लिकेट होती हैं, और एक दोहराव कुछ नया नहीं लिखता लेकिन फिर भी 200 लौटाता है।
  • Google Play डिलीवरी Pub/Sub messageId पर डीडुप्लिकेट होती हैं, किसी भी प्रोसेसिंग से पहले जाँची जाती हैं।
  • खरीद स्थिति purchaseToken या originalTransactionId पर कुंजीबद्ध होती है, ताकि क्रम-से-बाहर घटनाएँ एक ही रिकॉर्ड पर उतरें।
  • हर रिफंड साइड इफ़ेक्ट, रद्द करना, घटाना, या उलटना, एक से अधिक बार चलाने के लिए सुरक्षित है।
  • आपका हैंडलर स्वीकृति देने से पहले इवेंट लिखता है, बाद में कभी नहीं।
  • दोहराई गई CONSUMPTION_REQUEST को अलग प्रॉम्प्ट के रूप में माना जाता है, डुप्लिकेट के रूप में नहीं, ताकि कोई खुली रिफंड विंडो न गिरे।

जानबूझकर अपने ही webhook से एक डुप्लिकेट गुज़ारें और देखें कि दूसरी बार वह कुछ नहीं बदलता। यही पूरा परीक्षण है। एक रिफंड हैंडलर जो दो बार हिट करने के लिए सुरक्षित है, वह वही है जिसकी चिंता आप उसी पल छोड़ सकते हैं जब कोई स्टोर उसे छह बार हिट करने का फ़ैसला करता है।

अक्सर पूछे जाने वाले सवाल

मेरा सर्वर वही App Store रिफंड सूचना एक से अधिक बार क्यों प्राप्त करता है?
क्योंकि Apple एक App Store Server Notification V2 को पाँच बार तक दोबारा भेजता है, पिछले प्रयास के 1, 12, 24, 48, और 72 घंटे बाद, जब भी आपका सर्वर 200 और 206 के बीच के किसी HTTP status के साथ जवाब नहीं देता। हर रिट्राई वही notificationUUID लेकर आती है, इसलिए आप उसे पहचानकर छोड़ सकते हैं।
App Store Server Notifications को डीडुप्लिकेट करने के लिए मुझे कौन सा फ़ील्ड उपयोग करना चाहिए?
notificationUUID का उपयोग करें। एक असली रिट्राई हमेशा वही notificationUUID दोहराती है, जबकि हर सचमुच नई घटना, जिसमें हर नया CONSUMPTION_REQUEST शामिल है, एक अलग पाती है, इसलिए notificationUUID पर डीडुप्लिकेट करने से दोहराव छूट जाते हैं बिना अलग घटनाओं को गिराए।
क्या दोहराई गई CONSUMPTION_REQUEST सूचनाएँ डुप्लिकेट हैं जिन्हें मुझे अनदेखा करना चाहिए?
नहीं। Apple खुली रिफंड विंडो में समय-समय पर नई CONSUMPTION_REQUEST सूचनाएँ भेजता है, और Apple के स्टाफ़ पुष्टि करते हैं कि ये रिट्राई नहीं हैं। हर एक का अपना notificationUUID होता है, इसलिए हर एक को प्रोसेस करें। उन्हें गिराने से Apple द्वारा जवाब देने के लिए दी गई 12-घंटे की विंडो चूकने का जोखिम है।
मैं Google Play Real-time Developer Notifications को कैसे डीडुप्लिकेट करूँ?
हर सूचना से Pub/Sub messageId पढ़ें और कार्रवाई करने से पहले उसे उन के विरुद्ध जाँचें जिन्हें आप पहले ही प्रोसेस कर चुके हैं, क्योंकि Pub/Sub कम-से-कम-एक-बार पहुँचाता है और वही संदेश एक से अधिक बार भेज सकता है। Google डुप्लिकेट प्रोसेसिंग और बर्बाद API कोटा से बचने के लिए इसकी स्पष्ट रूप से सिफ़ारिश करता है।
क्या मुझे किसी डुप्लिकेट रिफंड सूचना को अस्वीकार करने के लिए एरर लौटाना चाहिए?
नहीं। एक 4xx या 5xx लौटाना स्टोर को बताता है कि डिलीवरी विफल हुई, इसलिए वह फिर भी दोबारा भेजता है। अपने ही डेटाबेस के भीतर डीडुप्लिकेट करें और हमेशा एक सफलता status लौटाएँ, Apple के लिए HTTP 200 से 206 या Google Play पुश के लिए एक 200 स्वीकृति।

स्रोत और आगे की जानकारी

RefundHalt

App Store और Google Play के लिए refund ऑटोपायलट

आगे पढ़ें

Deep diveपढ़ने में 8 मिनट

Family Sharing रिफंड एक भुगतान को पलट देता है, लेकिन पाँच अन्य लोगों को अब भी आपकी ऐप इस्तेमाल करते हुए छोड़ सकता है, और केवल आपका सर्वर ही उन्हें रोक सकता है

एक Family Sharing रिफंड एक भुगतान को पलट देता है, लेकिन पाँच तक परिवार के सदस्यों को आपके पेड फ़ीचर्स पर बनाए रख सकता है. Apple एक REVOKE भेजता है और उम्मीद करता है कि आपका सर्वर उस एक्सेस को खत्म करे. यहाँ बताया गया है कि परिवार में साझा किए गए रिफंड कैसे काम करते हैं और एक की कीमत क्या है.

Playbookपढ़ने में 8 मिनट

रिफंड हैंडलिंग चुपचाप टूटती है, इसलिए किसी असली ग्राहक से पहले sandbox में in-app purchase रिफंड टेस्ट करें

आपकी रिफंड हैंडलिंग तभी चलती है जब ग्राहक पहले ही जा चुका होता है, इसलिए इसमें कोई बग असली पैसे खर्च होने तक अदृश्य रहता है। दोनों स्टोर आपको पहले एक टेस्ट माहौल में रिफंड ट्रिगर करने देते हैं। यहाँ बताया गया है कि किसी रिफंड के असली होने से पहले App Store और Google Play पर in-app purchase रिफंड कैसे टेस्ट करें।

अगला refund अनुरोध पहले ही रास्ते में है.

RefundHalt को उतने समय में सेटअप करें, जितने में आप उस refund के बारे में एक और सपोर्ट ईमेल पढ़ते हैं जिस पर आपत्ति नहीं कर पाए.