Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to properly retrieve Query response after clearing cache #5343

Closed
YagiRyu opened this issue Nov 1, 2023 · 2 comments
Closed

Unable to properly retrieve Query response after clearing cache #5343

YagiRyu opened this issue Nov 1, 2023 · 2 comments

Comments

@YagiRyu
Copy link

YagiRyu commented Nov 1, 2023

Question

Version

4.0.0-beta2

Summary

Unable to properly retrieve Query response after clearing cache.
We are doing the following process.

Example code

fun customApolloClient(): ApolloClient {
    val memoryCacheFactory = MemoryCacheFactory(
        maxSizeBytes = 10 * 1024 * 1024,
        expireAfterMillis = TimeUnit.MINUTES.toMillis(5L)
    )

    val cacheResolver = object : CacheResolver {
        override fun resolveField(
            field: CompiledField,
            variables: Executable.Variables,
            parent: Map<String, Any?>,
            parentId: String
        ): Any? = field.resolveArgument("id", variables)?.toString()
            ?.let(::CacheKey)
            ?: FieldPolicyCacheResolver.resolveField(field, variables, parent, parentId)
    }

    val cacheKeyGenerator = object : CacheKeyGenerator {
        override fun cacheKeyForObject(
            obj: Map<String, Any?>,
            context: CacheKeyGeneratorContext
        ): CacheKey? {
            return obj["id"]?.toString()?.let { CacheKey(it) }
                ?: TypePolicyCacheKeyGenerator.cacheKeyForObject(obj, context)
        }
    }

    return ApolloClient.Builder()
        .serverUrl(BuildConfig.ENDPOINT)
        .logCacheMisses()
        .normalizedCache(
            normalizedCacheFactory = memoryCacheFactory,
            cacheKeyGenerator = cacheKeyGenerator,
            cacheResolver = cacheResolver
        )
        .ktorClient(HttpClient())
        .build()
}

@Composable
fun <D : Query.Data> ApolloClient.query(
    q: Query<D>,
): ApolloResponse<D>? {
    val keys = arrayOf(q.hashCode())
    val apolloResponseFlow = remember(keys = keys) {
        query(q).watch()
    }

    val apolloResponse by apolloResponseFlow.collectAsState(initial = null)
    return apolloResponse
}

@Composable
fun Root() {
    val customClient = customApolloClient()
    Main(customClient)
}

@Composable
fun Main(
    customClient: ApolloClient
) {
    customClient.query(q = AppifyAppQuery())?.let { appifyQuery ->
        NavHostComposable(customClient = customClient)
    } ?: Unit
}

@Composable
fun LogoutPage(
    customClient: ApolloClient,
    navController: NavController,
) {
    Scaffold {
        Column(
            modifier = Modifier.padding(it)
        ) {
            Button(onClick = {
                customClient.apolloStore.clearAll()
                navController.navigate(NavItem.AfterDemo)
            }) {
                Text(text = "Logout button")
            }
        }
    }
}

@Composable
fun AccountPage(
    customClient: ApolloClient,
) {
    customClient.query(q = AppifyAccountPageQuery())
    Scaffold {
        Column(
            modifier = Modifier.padding(it)
        ) {
            Text(text = "Account Page")
        }
    }
}

Clear the cache from the Logout component and move to the Account component; when the query function is called in the Account component, it is called up to the query function in the Main component, which returns null and the screen goes blank.
In the Account component, a successful response is returned, but the query function in the Main component is called immediately thereafter.
In the v.3.8.2 series, the query function of the Main component was never called until the query function of the Main component, but after upgrading to v4.0.0-beta2, it is called for some reason.
It seems to be caused by updating the cache, how can I prevent this problem?

@martinbonnin
Copy link
Contributor

Hi 👋 This is most likely the result of the error handling changes. In v4, cache misses are emitted with response.data = null and a response.exception is CacheMissException.

There's more background in the RFC but the tldr; is that it exposes more information to the callers and make it easier to react to cache misses.

If you want to ignore the cache misses, you can do so by filtering out the cache misses:

query(q).watch().filter { 
   it.exception !is CacheMissException
} 

Let us know how that works!

@YagiRyu
Copy link
Author

YagiRyu commented Nov 4, 2023

@martinbonnin
Thank you for your advice.
We have tried it with our code and successfully solved the problem!
Thank you so much!

@YagiRyu YagiRyu closed this as completed Nov 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants