https://kotlinlang.org logo
#apollo-kotlin
Title
# apollo-kotlin
s

Stylianos Gakis

12/07/2023, 4:26 PM
When I am doing a
watch
on a query, smth like this
Copy code
apolloClient.query(MyQuery)
      .fetchPolicy(FetchPolicy.CacheOnly)
      .watch(true, true) // also tried with `watch(true, true)` etc.
      .onEach {
        logcat { "watchMessages: #1" }
      }
      .retryWhen { cause, _ ->
        cause is CacheMissException ||
          (cause is ApolloCompositeException && cause.suppressedExceptions.any { it is CacheMissException })
      }
      ...
I was testing the “I have no internet at all” scenario here and I have turned off wifi + data completely, and it seems to just never emit anything, which I am not sure I understand why. It never reaches the first onEach to log #1 In the scenario where there’s nothing in the cache, should it not at least either throw a
CacheMissException
or just emit an empty list or something like that? If there is already something in the cache, should it not just try and emit what was in the cache already? And I made sure that there is no problem with the flow itself never turning hot by doing smth silly like
Copy code
return flow {
      logcat { "watchMessages: #0.5" }
      emitAll(<the snippet above>)
}
and #0.5 is printed correctly, so for sure the flow starts.
1
Can you imagine a scenario where this is possible to happen? I feel like I am lacking some fundamental understanding of how
watch
works here perhaps. I am on
3.8.2
btw atm
m

mbonnin

12/07/2023, 4:33 PM
watch swallows errors by default on v3
You have a
fetchThrows
param to workaround that
But v4 is going to be a lot better in that regard
s

Stylianos Gakis

12/07/2023, 4:39 PM
Right, but even with
.watch(fetchThrows = true, refetchThrows = true)
passed there I see no emissions on the
logcat { "watchMessages: #1" }
, I would be able to see it if it did in fact throw there right? And it should the fall down to my
retryWhen
, if I understand flows correctly 😄
Right, I should’ve added my log
inside
the retryWhen, there I can actually see that it gets emitted at least. Otherwise the first onEach just gets skipped I suppose, since there is an exception falling downwards, not a value! So you are totally right, I get the exception when I am asking it to throw the exception (obviously 😂)
And yes, I am getting like 1 million logs per second when I move the log inside the retryWhen, since I add no backoff 😄
Thanks for making me see straight here! I think what I want here is then to fetch on initial fetches, and emit a default value in that case, and let it retry after a bit of a delay. I am listening to the cache for chat messages here, and having no messages should just be a perfectly fine scenario. I just need it to emit something initially so that I know if we got some messages or not This https://github.com/HedvigInsurance/android/commit/79edb37e58cc05f1731a60d958c2f4ffd1f92bfc worked wonders 🤩 with this as context, is it right to check for CacheMissException like this?
Copy code
.retryWhen { cause, _ ->
        val shouldRetry = cause is CacheMissException ||
          (cause is ApolloCompositeException && cause.suppressedExceptions.any { it is CacheMissException })
I am afraid I will miss it otherwise if it’s inside a
ApolloCompositeException
which I am not 100% confident that it’s impossible to get here, so I wanted to be safe rather than sorry
m

mbonnin

12/07/2023, 11:14 PM
```cause is CacheMissException ||
(cause is ApolloCompositeException && cause.suppressedExceptions.any { it is CacheMissException })```
I don't think you need the
ApolloCompositeException
here since your fetch policy is
CacheOnly
ApolloCompositeException
is only for
CacheFirst
NetworkFirst
and
CacheAndNetwork
(and it's also going away in v4)
s

Stylianos Gakis

12/07/2023, 11:36 PM
Yeah I added it basically out of fear that I don't understand under which circumstances a composite exception could be thrown. But super good to know it's gone in V4, one less thing which is a bit unclear. Is that gone in V4 because it's modeled in some different way? Or because in general Apollo then tries to do a lot less with exceptions in general?
m

mbonnin

12/07/2023, 11:42 PM
A bit of both I would say?
ApolloCompositeException
only existed as a way to surface exceptions if both fetches fail in a
CacheFirst
query for an example
In v4, because the cache misses and network errors are emitted, it's not needed at all
thank you color 1
The cache misses and network errors are surfaced to the user that can decide what they want to do with them