Hi all, is it possible to supervise an object betw...
# coroutines
a
Hi all, is it possible to supervise an object between different coroutines? My service is acting as a gateway between a frontend and other http apis. So I represent each Http Api as an object, and I reuse http client instances like this:
Copy code
object HttpApi {

    private val httpClient = httpClient {
        it.followRedirects = false
    }

    private suspend fun <T> httpClientWithLogin(work: suspend (HttpClient) -> T): T {
            httpClient.login()
            return work(httpClient)
    }

   suspend fun someApiMethod(): Result = httpClientWithLogin { client ->
      ...
   } 
}
The problem is, that the httpClient might become unusable, e.g. because it is closed for whatever reason. I want to protect against that by recreating the httpClient instance. So I am doing this:
Copy code
object HttpApi {

    private var httpClient = recreateHttpClient()

    private fun recreateHttpClient() = httpClient {
        it.followRedirects = false
    }

    private suspend fun <T> httpClientWithLogin(work: suspend (HttpClient) -> T): T {
           return try {
            httpClient.login()
            work(htpClient)
        } catch (e: Exception) {
            log.error("Recreating HTTP client", e)
            httpClient = recreateHttpClient()
            throw e
        }
    }

   suspend fun someApiMethod(): Result = httpClientWithLogin { client ->
      ...
   } 
}
I don't particularly like it. For one, I am not sure whether I get multi-threading problems with recreateHttpClient. Also, if a call fails, it is not immediately retried. Can this be handled more elegantly with supervisor coroutine scope? How would you approach this scenario?
d
Maybe don't make it a global singleton. Go with a top-level singleton.
d
You can use a
suspend fun getHttpClient(): HttpClient
that is implemented with whatever thread safe or local logic to test if a cached client is valid before returning it.