How the retry should be implemented?

Hi,

I am bit lost what are the ways to implement retry logic.

I have a simple code like this

 val response = runBlocking {
        val mutation = apolloClient.mutation(
          UpdateCollectionMainStageMutation(
            input = it.first,
            version = version,
            metadata = Optional.present(it.second)
          )
        )
        mutation.execute()
      }

I see the there were some suggestions from old github comments, but not sure if they are accurate.

I see in the doc for react Retry Link - Apollo GraphQL Docs , is there something for Kotlin?

1 Like

Hi!

If you only need to retry certain operations on a case-by-case basis, you can simply enclose the call to execute into a try catch block and treat the exception here. Also check response.errors for GraphQL errors. It could be an extension on ApolloClient to be nicer to use, something like:

suspend fun <T : Query.Data> ApolloClient.tryQuery(query: Query<T>, retryCount: Int): T? {
    for (i in 0..retryCount) {
        val response = try {
            this.query(query).execute()
        } catch (e: Exception) {
            // Log the errors
            continue
        }
        if (response.hasErrors()) {
            // Log the errors
            continue
        }
        return response.data
    }
    return null
}

If you want to have this behavior for all operations, you can use an ApolloInterceptor for this, which will be automatically be called for all operations. Something like this:

class RetryInterceptor(private val retryCount: Long) : ApolloInterceptor {
    override fun <D : Operation.Data> intercept(
        request: ApolloRequest<D>,
        chain: ApolloInterceptorChain
    ): Flow<ApolloResponse<D>> {
        return chain.proceed(request)
            .onEach { response ->
                if (response.hasErrors()) {
                    throw Exception("There were GraphQL errors")
                }
            }
            .retry(retryCount) { true }
    }
}

and use it on your client like this:

    val apolloClient = ApolloClient.Builder()
        .serverUrl("https://...")
        .addInterceptor(RetryInterceptor(3))
        .build()

Hi @Benoit_Lubek
Using the RetryInterceptor example above, would it retry for Network Errors ? Ideally doesn’t it make sense to retry only Network Errors ? Is there any scenario where retrying GraphQL Errors help ?

Reference Error Handling doc : Error handling - Apollo GraphQL Docs

Hi!

In the code above, both GraphQL and network errors would cause a retry, but it doesn’t necessarily makes sense to do that - in most cases you probably won’t want or need to do that, or at least do it only on certain classes of errors only (I can imagine some “Backend temporary failure, please retry” types of errors for instance). Ultimately that depends on your project’s specific needs.