Apollo-ios: GraphQLQueryWatcher - fetch and watch flow.

Created on 5 Aug 2020  路  6Comments  路  Source: apollographql/apollo-ios

Let's discuss watchers, cache and their flow.

Cold start of application - no cache at all.
Here are my debug logs:

isReachable true                         //Reachability change
User: nil                                      //No user logged in        
apollo.watch(query: SyncManagerQuery(), cachePolicy:  .returnCacheDataDontFetch)     
Watch SyncManagerQuery       // We are interested ONLY in cached data.
Watch SyncManagerQuery error   //Error cache is empty. It's ok
Missing value                                 //Error description - missing value. Because cache is empty. 

Here everything seems to be fine. We are starting application for the first time. Cache is empty. Query watcher is being triggered and is returning error because of lack of data in cache.

Now let's move forward and log in.

Optional(<FIRUser: 0x6000031c6000>)          //Now we've got user
fetch. apollo.fetch(query: SyncManagerQuery(), cachePolicy: .fetchIgnoringCacheData)  
Fetch Sync FETCH                                             //Ignoring cache data is still creating cache am I right?
Sync Fetch success                                          //Fetch is successful 
BUT NOTHING IS HAPPENING :(

Question 1: Why watcher is not reacting? It is being stored in a parent object.
private var syncWatcher: GraphQLQueryWatcher<SyncManagerQuery>?
and is initialized before fetch trigger.

Ok let's start over again. Close the application and start again with already existing cache.

isReachable true                                           //We've got internet
Optional(<FIRUser: 0x600003eba480>)    //We've got user
Fetch Sync FETCH                                       //Above conditions are triggering FETCH
Watch SyncManagerQuery                          //Hmm watch is also starting? Not that scary ok, it is just executing for the first time?
Watch SyncManagerQuery success          //Success - because we already have cache so it's ok
Sync Fetch success                                   //In the meantime FETCH just finished
Watch SyncManagerQuery                       // **1***  So it is triggering watch. Not sure why.
Watch SyncManagerQuery error            //Error :(The operation couldn鈥檛 be completed. (Apollo.URLSessionClient.URLSessionClientError error 2.)  **2**
Watch SyncManagerQuery                      // But hey it is trying once again 
Watch SyncManagerQuery success       // And this time we've got a success.

Question 2: - Fetch result had no changes at all. It was exactly the same. Is watcher reacting to just cache update or is it verifying actual changes?
Question 3: - Why it fails? And the retry is normal behavior after failure or is it a side effect of sth else?

Ok let's start over again. Exactly same conditions. We already have cache.


isReachable true                                             //We've got internet
Optional(<FIRUser: 0x6000008ce080>)      //We've got user
Fetch Sync FETCH                                         //Starting fetch
Watch SyncManagerQuery                            
Watch SyncManagerQuery success             //Watching cache successful
Sync Fetch success                                      //Fetching data successful, cache is being refreshed
Watch SyncManagerQuery                           //And this is probably triggering watch 
Watch SyncManagerQuery success            //Watch is successful
Watch SyncManagerQuery                          //**1** But what is happening? Why it is triggering once again?
Watch SyncManagerQuery success

Question 4: - why my watch query seems to be triggering twice after fetch?

caching question

All 6 comments

Hi! I renumbered your questions so it would be clearer which one i'm responding to once I get more information here. Some things that would be helpful to understand:

  • Are you using the SQLite cache or the in-memory cache?
  • In the second code block (just before question 1), you are still running the watcher which was started in the first code block, and that's what you're expecting to get hit when you've added "But nothing is happening", correct?
  • After Question 1, you say "close the application and start again" - do you mean that you just exit the application then go back into it, or that you force-quit the application?
  • For the 3rd and 4th sets of logs, are you specifying a cache policy or using the default .returnCacheDataElseFetch?
  • Where in the application lifecycle are you setting up your watcher? Is it possible that the watcher could be getting set up multiple times?
  1. SQLite cache
  2. That is the same app session. So yeah watcher is still up and running.
  3. Reset the application. New session. SQLite cache already exists. Just wanted to check how watcher is going to act with existing cache and initializing once again.
  4. Watch is always using returnCacheDataDontFetch, fetch is alwasy using fetchIgnoringCacheData
  5. Not possible in that case. My AppDelegate is starting the whole FlowControlAgent which is Singleton here.

All problems seems to be similar to "cold start" problem described here
https://github.com/apollographql/apollo-ios/issues/99

Yeah, this from @martijnwalraven in #99 definitely seems to explain why your first watcher isn't called:

Because your watch uses .returnCacheDataDontFetch, and the cache is initially empty, it will never get a valid response in that case.

Is there a chance you could send me a small repro project? I should at least be able to try to figure out why the watch is getting called twice, but it'd be pretty hard to do without something to debug. You can email it to ellen at apollographql dot com.

I'll do my best to prepare some sample however now I'm out of time. Hopefully will send you sth around weekend.
Right now, well, I can live with double watcher :)

@pgawlowski Were you ever able to get a sample together? If not, do you mind if we close this issue out?

Hey @designatednerd

Sorry for not providing my sample code. It's still on my personal ToDo however I am totally sucked into other work. Let's close this issue right now. Hope I will provide some sample that will be helpful to validate this issue in some time - maybe during my vacations :)

Thanks for everything!

Was this page helpful?
0 / 5 - 0 ratings