title: Cancellation in Coroutines and Okhttp
body: <p>So I'm playing around using Coroutines and Okhttp to connect a websocket.</p>
  
  <h1>What I've done</h1>
  
  <pre><code>// initialise okhttp
  fun provideOkHttpClient(): OkHttpClient {
          return OkHttpClient.Builder()
              .addInterceptor(RetryInterceptor())
              .build()
  }
  
  // RetryInterceptor.kt
  class RetryInterceptor : Interceptor {
  
      companion object {
          private const val RETRIES_LIMIT = 4
      }
  
      override fun intercept(chain: Interceptor.Chain): Response {
          val request = chain.request()
          var retries = 0
  
          var response: Response?
          response = sendRequest(chain, request)
  
          while (response == null &amp;&amp; retries &lt;= RETRIES_LIMIT) {
              retries++
              val sleepTimer = 2.toDouble().pow(retries.toDouble())
              Log.d("OkhttpClient", "Connection failed, retry in ${sleepTimer}s")
              Thread.sleep(sleepTimer.toLong() * 1000)
              response = sendRequest(chain, request)
          }
  
          return response ?: Response.Builder()
              .request(request)
              .code(400)
              .build()
      }
  
      private fun sendRequest(chain: Interceptor.Chain, request: Request): Response? {
          val response: Response
          return try {
              response = chain.proceed(request)
              if (!response.isSuccessful) null else response
          } catch (e: IOException) {
              null
          }
      }
  }
  
  // define a exception handler
  val handler = CoroutineExceptionHandler { _, throwable -&gt;
          when (throwable) {
              is CancellationException -&gt; {
                  // cancel the socket connection here
                  Log.d("CancellationException", "cancelled")
              }
              else -&gt; onRegisterError(
                  throwable.localizedMessage ?: "Coroutine Error"
              )
  
          }
      }
  
  // Then inside ViewModel, fire up the okhttp client
  val viewModelScopeJob = viewModelScope.launch(context = handler) {
  
              val someOtherJob = otherContext.launch {
                  // launch suspend fun connectSocket()
              }
  
          }
  // Then call cancel inside ViewModel like this:
  viewModelScopeJob.cancel()
  </code></pre>
  
  <h1>Problem</h1>
  
  <p><code>viewModelScopeJob</code> is a parent job, when the <code>cancel()</code> is being called, it should cancel its child-jobs and invoke the <code>CancellationException</code>, however it doesn't.</p>
  
  <h1>Question</h1>
  
  <p>So the coroutine job will not be cancelled because of <code>Thread.sleep()</code> inside interceptor is not cooperative. </p>
  
  <p>My questions is: given <code>RetryInterceptor</code> is located in a separate class, I'm not be able to use methods like <code>delay()</code>, how should I change my code in order to cancel the retry when <code>viewModelScopeJob.cancel()</code> is called?</p>