Zaman aşımı değeri ile eşzamanlı olarak eşzamansız istek nasıl çağrılır?

Jan 07 2021

Zaman uyumsuz bir API isteğini eşzamanlı olarak çağırmam gerekiyor. Bu api isteğinin yanıtlanması uzun zaman aldığından, api-isteğinin başarısız olması ve null ile devam etmesi için bir zaman aşımı ayarlamak istiyorum. İşte bu api'yi aramak için kodum:

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()
        }
    }
}

Nasıl External3rdPartyApiçalıştığını değiştiremem .

Bence yukarıdaki kod kötü görünüyor. Ayrıca başka bir cevapta okudum :

withTimeout { ... }yalnızca söz konusu işlem iptal edilebilirse mümkün olan zaman aşımıyla devam eden işlemi iptal etmek için tasarlanmıştır .

Öyleyse, suspendCancellableCoroutineyerine kullanmalı suspendCoroutinemıyım?

Nasıl daha iyi yazabilirim?

Yanıtlar

1 ChristianB Jan 07 2021 at 19:42

Kullanımı suspendCoroutinegayet eğer eşyordamın değil (ya istemiyorum) kolu iptali can. Ancak bir zaman aşımınız olduğu için, suspendCancellableCoroutine'i kullanmayı düşünmeli ve işi durdurmak için cancelation olayını işlemelisiniz (mümkünse üçüncü taraf işlevinde).

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

Üçüncü taraf işleviniz bir istisna attığında, onu yakalamayı deneyebilir ve ile devam ettirerek exceptionveya bir nulldeğer döndürerek devam ettirmeyi bitirebilirsiniz (kullanım durumunuza bağlıdır):

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)
  }   
}

Hepsini bir araya getirelim

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
      }
    }
  }
}