firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.81k stars 884 forks source link

Safari gets stuck when using cache #8081

Open cherylEnkidu opened 5 months ago

cherylEnkidu commented 5 months ago

Operating System

MacOS Sonoma 14.4

Browser Version

Safari 17.4

Firebase SDK Version

10.8.0

Firebase SDK Product:

Firestore

Describe your project's tooling

NA

Describe the problem

Context: https://github.com/firebase/firebase-js-sdk/issues/7940 Internal tracking ticket: b/330146982, b/330181199

A developer, @jmw11x reports Safari getting stuck when using cache.

After initial investigation, the root cause is data stored in cache on Safari lost at some point. The problem is related to Safari indexdb issue. The Firestore SDK team hasn't find work around so far.

Steps and code to reproduce issue

The issue can be consistently reproduced on Safari using developer's repo App : https://github.com/jmw11x/FirebaseFirestore-Case-10271607/tree/main

pJimenezProadata commented 3 months ago

Are there any news on this issue? We are using this library on an Ionic Capacitor app for iOS and the problem still persists. Thank you!!

cherylEnkidu commented 3 months ago

@pJimenezProadata

Unfortunately the team doesn't have a workaround so far.

tobylewis commented 1 month ago

This has cost me days and significant frustration.

Firebase seems to get stuck right at the beginning. Clearing caches from the Safari developer menu, or clear history, immediately unblocks any pending queries etc.

As a workaround I set a timeout before calling onSnapshot() and clear it in the callback.

let fix:any = setTimeout(() => {
    localStorage.setItem('safari-reset', String(Date.now()))
    window.location.reload()
}, 5000) // 5 second timeout
onSnapshot((snaps)=>{
    if (fix) {
        clearTimeout(fix)
        fix = false
    }
    // process snaps
}

If firebase is not responding then the timeout fires setting a flag and reloading the page.

When initialising firebase after reload I use the memoryLocalCache() instead of persistentMultipleTabManager() if it has failed in the last five minutes.

let localCache: any = persistentLocalCache({ tabManager: persistentMultipleTabManager() })
if (Number(localStorage.getItem('safari-reset')) > (Date.now() - 300000)) { // five minutes
    localCache = memoryLocalCache()
}
initializeFirestore(app, { localCache })

Not ideal but gets the app working on safari. I actually show the user a confirmation dialog before doing the reload so they know why it is reloading and to prevent infinite looping if something else has gone pear shaped.

cherylEnkidu commented 1 month ago

Hi @tobylewis,

Thank you so much for providing your workaround to help other developers! Could you please help our team verify if you just use persistentMultipleTabManager() and not ask the page the force reload, will that solve the problem?

tobylewis commented 1 month ago

Hi @cherylEnkidu I use persistentMultipleTabManager() as default because I want the data persisted all the time. The problem is that sometimes the request seems to get stuck in the cache retreival and never pings the server nor returns a result to my call. So when fails (using a setTimout() I detect a long delay after making firestore query) I downgrade to memoryLocalCache().

It's my understanding I can only only set the localCache with initializeFirestore() and this can only be called before any other firestore commands. Therefore I need to reload the page in order to call this again.

cherylEnkidu commented 1 month ago

Hi @tobylewis ,

Thank you for you detailed and quick explanation.

The problem you are running into seems to be different from this open ticket. In the ticket's case, cache on Safari lost at some point but it won't make request pending. Could you please open a new ticket to provide us a repo / log? Also could you please help us check your issue only happened with Safari but not other browsers?