एक टाइमआउट मान के साथ अतुल्यकालिक अनुरोध को कैसे कॉल करें?

Jan 07 2021

मुझे एक एसिंक्रोनस एपि अनुरोध को सिंक्रोनाइज़ करना है। चूंकि यह एपीआई अनुरोध का जवाब देने में लंबा समय लेता है, इसलिए मैं एपीआई-अनुरोध को विफल करने और अशक्त रहने के लिए एक समय निर्धारित करना चाहता हूं। यहाँ इस एपीआई को कॉल करने के लिए मेरा कोड है:

private suspend fun call(
    accessStage: AccessStage,
): Response? = withContext<Response?>(Dispatchers.IO) {

    return@withContext withTimeoutOrNull(1000) {

        suspendCoroutine<Response?> { continuation ->

            val request = External3rdPartyApi.newRequest(
                accessStage
            ) { response, throwable ->

                continuation.resume(response)
            }

            request.parameters = hashMapOf<String, String>().apply {
                put["token"] = External3rdPartyApi.TOKEN
                put["salt"] = External3rdPartyApi.calculateSalt(accessStage)
            }
            request.executeAsync()
        }
    }
}

मैं यह नहीं बदल सकता कि कैसे External3rdPartyApiकाम करता है।

मुझे लगता है कि ऊपर कोड बुराई लग रहा है। इसके अलावा, मैंने एक अन्य उत्तर में पढ़ा :

withTimeout { ... }टाइमआउट पर चल रहे ऑपरेशन को रद्द करने के लिए डिज़ाइन किया गया है, जो केवल तभी संभव है जब प्रश्न में ऑपरेशन रद्द हो

तो, के suspendCancellableCoroutineबजाय मैं का उपयोग करना चाहिए suspendCoroutine?

मैं इसे बेहतर तरीके से कैसे लिख सकता हूं?

जवाब

1 ChristianB Jan 07 2021 at 19:42

का उपयोग करना suspendCoroutineठीक है अगर आप कर सकते हैं (या नहीं करना चाहते हैं) Coroutine का रद्दकरण। लेकिन क्योंकि आपके पास एक टाइमआउट है, तो आपको काम को रोकने के लिए सस्पेंड कांस्टेबलकोराटाइन का उपयोग करने पर विचार करना चाहिए और रद्द करने की घटना को संभालना चाहिए (तीसरे पक्ष के कार्य में - यदि आप कर सकते हैं)।

suspendCancellableCoroutine<T> { continuation ->
  continuation.invokeOnCancellation { throwable ->
    // now you could stop your (third party) work  
  }        
}

जब आपका थर्ड पार्टी फंक्शन एक अपवाद फेंकता है, तो आप इसे आज़मा सकते हैं और अपना रेज्यूमे या तो फिर से शुरू कर सकते हैं या मान exceptionवापस कर सकते हैं null(आपके उपयोग मामले पर निर्भर करता है):

suspendCancellableCoroutine<T?> { continuation ->
  try {
    continuation.resume(thirdParty.call())
  } catch (e: Exception) {
    // resume with exception
    continuation.resumeWithException(e)
    // or just return null and swallow the exception
    continuation.resume(null)
  }   
}

चलो सब एक साथ डाल दिया

suspend fun call(): Response? = withContext(Dispatchers.IO) {
  return@withContext withTimeoutOrNull(1000L) {
    return@withTimeoutOrNull suspendCancellableCoroutine { continuation ->
      try {
        continuation.resume(External3rdPartyApi.newRequest(accessStage))
      } catch (e: Exception) {
        // resume with exception
        continuation.resumeWithException(e)
        
        // or just return null and swallow the exception
        continuation.resume(null)
      }
         
      // in case the coroutine gets cancelled - because of timeout or something else
      continuation.invokeOnCancellation {
        // stop all the work
      }
    }
  }
}