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

FR: Be able to invalidate offline data #1180

Closed
shaharyakir opened this issue Apr 25, 2018 · 6 comments
Closed

FR: Be able to invalidate offline data #1180

shaharyakir opened this issue Apr 25, 2018 · 6 comments

Comments

@shaharyakir
Copy link

Consider a case where we have some kind of data discrepancy which causes crashes in our clients.

The problem is identified and fixed at our remote Firestore DB, but since clients maintain and read offline data first,

users keep processing the offline data on startup and therefore crash.

I tried playing with listening to metadata changes and ignoring offline data when the app starts after a crash, but could only do it for snapshot listeners and not for fetches.

I'd like to be able to invalidate offline data for crashing clients (i.e. in the Crashlytics delegate method).

@wilhuff
Copy link
Contributor

wilhuff commented Apr 25, 2018

This is a pretty interesting idea.

We have a feature queued up for the next release (merged in PR #1096) that adds the ability to specify a preference for get operations.

We've also discussed exposing an API to delete all local storage as a kind of nuclear option. We would consider this a feature mostly for testing, but would also work in this case. There's been some discussion about this in the javascript repo but the discussion applies equally here, substituting LevelDB for IndexedDB.

Meanwhile, note that the Firestore offline cache is just a LevelDB database stored as files. You can delete these before you start Firestore. You can see how we figure the directory to store them here:

https://github.com/firebase/firebase-ios-sdk/blob/master/Firestore/Source/Local/FSTLevelDB.mm#L108

Note that we're investigating changing this location from Documents to Library/Application Support so you'll need to pay attention to our release notes if you choose to reach under the covers like this.

I'll leave this open essentially as an iOS-specific copy of firebase/firebase-js-sdk#449.

@shaharyakir
Copy link
Author

Does #1096 (I guess it's #655) also cover snapshot listeners or only fetches?

In any case I can see why it would be considered nuclear (i.e. internal?), but I feel as if the developer needs to have some kind of control in order to escape cases such as mentioned.

Will try deleting manually as suggested. Thanks.

@mikelehen
Copy link
Contributor

#655 is specifically for fetches via getDocument() / getDocuments(), but (as I think you already discovered) for a snapshot listener you can already check .metadata.isFromCache on the snapshots you get and ignore any snapshots from cache, waiting until you get a non-cache snapshot which will be fully up-to-date with the server data.

If you end up wiping persistence on crashes, I'd be curious to hear how that works out for you. It does seem like this might be a useful pattern for other apps to implement and so we may want to provide some guidance and/or make it easier in the future... So if you find something that works well, let us know.

@shaharyakir
Copy link
Author

You are correct but that would be a little bit cumbersome since:

  1. Different handling for fetches and listeners
  2. Need to use includeMetadataChanges only when crashes are involved, otherwise I won't get the remote data if it is not changed compared to local cache

I'm trying wiping now. Preliminary testing seems to work well, the only tricky thing is to track consecutive crashes with crashlytics - it makes more sense to clear cache after more than one consecutive crash.

Will keep you posted.

@shaharyakir
Copy link
Author

shaharyakir commented Apr 25, 2018

The code below seems to work well. Glad to hear your thoughts.

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

   ...

     myGlobalContext.isStartingAfterCrash = false

    // these trigger a synchronous call to delegate method below
    Crashlytics.sharedInstance().delegate = self
    Fabric.with([Crashlytics.self])

    // We know now delegate method has been called and can use the updated global context - if no previous crash was detected, we can safely reset the consecutive crash counter
    if !myGlobalContext.isStartingAfterCrash && myUserPrefsWrapper.consecutiveCrashes.value > 0 {
 
        myUserPrefsWrapper.consecutiveCrashes.value = 0
        
    }

    // decide whether to clear cache
    if myUserPrefsWrapper.consecutiveCrashes.value >= 2 {

      do {
        
        let fileManager = FileManager.default
        
        // Todo on every firebase sdk update make sure this wasn't changed
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
        
        let path = documentsPath.appending("/firestore")
        
        try fileManager.removeItem(atPath: path)
        
    } catch {
        
        print("\(error.localizedDescription)")
        
    }

    // now initialize firestore with offline persistence as usual
    ....

  }

  // Crashlytics Delegate method
  func crashlyticsDidDetectReport(forLastExecution report: CLSReport, completionHandler: @escaping (Bool) -> Void) {
    
    myGlobalContext.isStartingAfterCrash = true
  
    myUserPrefsWrapper.consecutiveCrashes.value = myUserPrefsWrapper.consecutiveCrashes.value + 1
  completionHandler(true)
    
  }

@thebrianchen
Copy link

clearPersistence() was released in v6.3.0.

@firebase firebase locked and limited conversation to collaborators Nov 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants