Firebase-js-sdk: Support Cloud Firestore Offline Persistence in Multiple Tabs

Created on 7 Oct 2017  路  39Comments  路  Source: firebase/firebase-js-sdk

Hi,

as pointed here:

If a user opens multiple browser tabs that point to the same Cloud Firestore database, and offline persistence is enabled, Cloud Firestore will work correctly only in the first tab.

Is it going to be addressed in future releases, or there is some limitation in browser's APIs that makes this issue impossible to resolve?

In Progress firestore

Most helpful comment

As of today, experimental multi-tab is available for you to play with. Please download Firebase Web 5.5.0 and enable multi-tab persistence as such:

db.enablePersistence({experimentalTabSynchronization: true})

Please do let us know if/what types of issues you encounter.

All 39 comments

Hey there! I couldn't figure out what this issue is about, so I've labeled it for a human to triage. Hang tight.

Hmmm this issue does not seem to follow the issue template. Make sure you provide all the required information.

We intend to support this in the future, but it's tricky since the tabs need to coordinate with each other to avoid clobbering each other's writes to the persisted data, etc. We do have a plan, but no concrete timeline yet.

Thank you for some feedback. Shall I leave this issue open until it's resolved?

Yep!

I am receiving the following error; while I am developing ionic/ angular app. But, i don't see any other tab open in chrome. what is the reason?

Uncaught (in promise): FirebaseError: [code=failed-precondition]: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled. FirebaseError: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled. at new FirestoreError (http://localhost:8100/build/vendor.js:21103:24) at http://localhost:8100/build/vendor.js:143420:42 at http://localhost:8100/build/vendor.js:23623:24 at PersistencePromise.wrapUserFunction (http://localhost:8100/build/vendor.js:23610:26) at PersistencePromise.wrapSuccess (http://localhost:8100/build/vendor.js:23622:25) at PersistencePromise._this.nextCallback (http://localhost:8100/build/vendor.js:23594:27) at PersistencePromise._this.isDone (http://localhost:8100/build/vendor.js:23566:23) at http://localhost:8100/build/vendor.js:23623:24 at PersistencePromise.wrapUserFunction (http://localhost:8100/build/vendor.js:23610:26) at PersistencePromise.wrapSuccess (http://localhost:8100/build/vendor.js:23622:25)

In the meantime, is it possible to disable offline persistence only when the user has multiple tabs open?

@Maistho Yes. Your .enablePersistence() call will fail (returning a rejected Promise) in the 2nd tab, but you can still use the client as usual (just without persistence).

Maybe something like this

@schmidt-sebastian @mikelehen
I'm very glad to see some initial work on this. Rest assured it's truly appreciated :+1:

Can we add a Status: In Progress label?

ERROR Error: Uncaught (in promise): FirebaseError: [code=failed-precondition]: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled.
FirebaseError: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled.

This is currently the intended behavior. There's been no release of this feature (nor is it complete).

Firestore (4.5.0) 2018-03-06T23:58:08.075Z: FirebaseError: [code=failed-precondition]: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled.

Two projects that were working stopped working in Chrome, now only work in firefox why?

As the error says, that means you have the project open in another tab (and it has offline persistence enabled). You should get the same error if you open two tabs in Firefox.

Or are you saying you're getting the error even though there is no existing tab open?

"Or are you saying you're getting the error even though there is no existing tab open?"
yes

mikelehen see :

https://www.youtube.com/watch?time_continue=1&v=Z09oq9aHpuA

ERROR Error: Uncaught (in promise): FirebaseError: [code=failed-precondition]: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled. FirebaseError: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled.

Thanks for the video (with music and everything)! That is very strange... I just tested and it works fine for me, which doesn't surprise me. My guess is somehow your Chrome is in a bad state, though it's pretty strange because that error should only happen if another tab has recently written an up-to-date timestamp (that's not in the future either) into IndexedDb. And so the client should recover from any sort of stale state that I can immediately think of.

Could you enable logging with firebase.firestore.setLogLevel('debug') and share the output (maybe throw it in a gist)? In particular I'm expecting a log line something like:

Valid owner already. Failing. Current owner: ...

Sure it is my browser, I asked other people online to test, all funcinou, this bug already consumed 8 hours of headache, Thanks for the help, you will not need the debug. Thank you !

(I am not part of this conversation but I just want to say @DevJoseWeb that bug video with the chill music is the most enjoyable user report I have seen in my 3.5 years of doing this job)

@DevJoseWeb If you're still able to reproduce it, I'd still be very interested in seeing the log output I mentioned. You are the second person to run into it, and I think there is probably some sort of bug here (or some sort of error condition we're not handling well), so I'd love to figure out what's going on.

I write this line firebase.firestore.setLogLevel ('debug') where? @mikelehen tanks @samtstern reggae !

contato.service.ts

`import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';

import { Contato } from './contato-model';

import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';

interface NewContato {
nome: string;
email: string;
celular: string;
mensagem: string;
area: string;
//id?: string;
time: number;
}

@Injectable()
export class ContatoService {

contatosCollection: AngularFirestoreCollection;
contatoDocument: AngularFirestoreDocument;

constructor(private afs: AngularFirestore) {
this.contatosCollection = this.afs.collection('contatos', (ref) => ref.orderBy('nome', 'desc').limit(10));
}

getData(): Observable firebase.firestore.setLogLevel('debug');
return this.contatosCollection.valueChanges();
}

getSnapshot(): Observable firebase.firestore.setLogLevel('debug');
return this.contatosCollection.snapshotChanges().map((actions) => {
return actions.map((a) => {
const data = a.payload.doc.data() as Contato;
return {
id: a.payload.doc.id,
nome: data.nome,
email: data.email,
celular: data.celular,
mensagem: data.mensagem,
area: data.area,
time: data.time
};

  });
});

}

getContato(id: string) {
firebase.firestore.setLogLevel('debug');
return this.afs.doc(contatos/${id});
}

create(
nome: string,
email: string,
celular: string,
mensagem: string,
area: string) {
const Contato = {
nome,
email,
celular,
mensagem,
area,
time: new Date().getTime(),
};
return this.contatosCollection.add(Contato);
}
/*
updateContato(id: string, data: Partial) {
return this.getContato(id).update(data);
}

deleteContato(id: string) {
return this.getContato(id).delete();
}
*/
}
`

@mikelehen the project: https://github.com/DevJoseWeb/site

I couldn't find the code you pasted in the https://github.com/DevJoseWeb/site project so I couldn't test, but I think you should be able to do something like:

import * as firebase from 'firebase/app';
import 'firebase/firestore';
firebase.firestore.setLogLevel('debug');

@mikelehen I have the same problem as @DevJoseWeb
I have a web based Ionic app that is built for Android. The problem only arrived when I recently updated Android System Web View. If I uninstall the update, the problem disappears.

Here is my full console log with log level set to debug:

[2018-04-23T19:30:09.773Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: Opening database: firestore/[DEFAULT]/swim-coach-62d6b/main vendor.js:142437 [2018-04-23T19:30:09.929Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: GET owner owner {"ownerId":"X4UFPtF3GDvFzKd84JCa","leaseTimestampMs":1524511458400} vendor.js:142437 [2018-04-23T19:30:09.943Z] @firebase/firestore: Firestore (4.10.1) [IndexedDbPersistence]: No valid owner. Acquiring owner lease. Current owner: {"ownerId":"X4UFPtF3GDvFzKd84JCa","leaseTimestampMs":1524511458400} New owner: {"ownerId":"BROWdCcPk9QpH4m5McjF","leaseTimestampMs":1524511809942} vendor.js:142437 [2018-04-23T19:30:09.953Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: PUT owner owner {"ownerId":"BROWdCcPk9QpH4m5McjF","leaseTimestampMs":1524511809942} vendor.js:142437 [2018-04-23T19:30:10.005Z] @firebase/firestore: Firestore (4.10.1) [IndexedDbPersistence]: Starting transaction: Start LocalStore vendor.js:142437 [2018-04-23T19:30:10.014Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: GET owner owner {"ownerId":"X4UFPtF3GDvFzKd84JCa","leaseTimestampMs":1524511458400} vendor.js:142437 [2018-04-23T19:30:10.021Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: Aborting transaction. polyfills.js:3 Unhandled Promise rejection: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled. ; Zone: <root> ; Task: IDBRequest.addEventListener:success ; Value: Error: There is another tab open with offline persistence enabled. Only one such tab is allowed at a time. The other tab must be closed or persistence must be disabled.

What can I do? As I said the app runs in standalone mode on Android so there is no other tab. I have many users of my app that experience the same problem. Please help!

By the way, if I clear the whole storage of the app and restart the app, I get another error:

[2018-04-23T19:37:19.583Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: Opening database: firestore/[DEFAULT]/swim-coach-62d6b/main vendor.js:142437 [2018-04-23T19:37:19.638Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: Database "firestore/[DEFAULT]/swim-coach-62d6b/main" requires upgrade from version: 0 vendor.js:142437 [2018-04-23T19:37:19.666Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: GET targetGlobal targetGlobalKey null vendor.js:142437 [2018-04-23T19:37:19.669Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: PUT targetGlobal targetGlobalKey {"highestTargetId":0,"highestListenSequenceNumber":0,"lastRemoteSnapshotVersion":{"seconds":0,"nanos":0},"targetCount":0} vendor.js:142437 [2018-04-23T19:37:19.676Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: COUNT targets vendor.js:142437 [2018-04-23T19:37:19.686Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: PUT targetGlobal targetGlobalKey {"highestTargetId":0,"highestListenSequenceNumber":0,"lastRemoteSnapshotVersion":{"seconds":0,"nanos":0},"targetCount":0} vendor.js:142437 [2018-04-23T19:37:19.693Z] @firebase/firestore: Firestore (4.10.1) [SimpleDb]: Database upgrade to version 2 complete main.js:98 Offline support not available (anonymous) @ main.js:98 vendor.js:142449 [2018-04-23T19:37:19.753Z] @firebase/firestore: Firestore (4.10.1): INTERNAL UNHANDLED ERROR: Version change transaction was aborted in upgradeneeded event handler.

@gizmodus This github issue is tracking the feature work to implement multi-tab support. It sounds like you are instead having an issue where with Ionic and a specific Android System Web View version, the client is incorrectly detecting multiple tabs in use. Offhand I don't know if this is something we'll be able to solve (perhaps it's a bug with Ionic or Android System Web View since it didn't happen before). Can you open a separate issue for this with more details (ideally a minimum repro that demonstrates the issue)?

@mikelehen I thought I'd post it here because it seemed as if you were waiting for the console output with 'debug' log level to the mentioned problem. I opened a new issue now.
Unfortunately, I can't create a repro of this as it only appears in the bundled version on Android (in Desktop chrome it works fine). I don't think this is related to Ionic, however it might also be a System WebView issue.
My hope is that you might find something in firestore's mechanism to check if multiple tabs are open, based on my log output. Any help is greatly appreciated!

@gizmodus Ahh, sorry. I forgot there'd been another related thread tacked onto this issue already. TBH that one should have been a separate issue as well. 馃槃 It's difficult to track issues when they get intermixed. Anyway, your log is interesting in that it suggest something impossible is happening (we overwrite a value in IndexedDb and then the old value somehow reappears). Either there's a bug in the Firestore SDK (so we're not actually overwriting the value even though the logs say we are) or in Android System WebView (our transaction is silently not getting persisted or something)... I'll see if we can get any more traction on the issue, but without a way to reproduce, it may be difficult.

@gizmodus Also, can you provide more information on "The problem only arrived when I recently updated Android System Web View. If I uninstall the update, the problem disappears." What exactly did you update and can you give the version that works and that doesn't? Thanks!

cc/ @schmidt-sebastian

@gizmodus Ah! I see you opened a new issue (#720). Thanks!

Any update on the timeline for multiple-tab persistence?

Doing development tears through my quota if I need to have multiple tabs of the application open or a user changes tabs.

We are actively working on adding support for multiple tabs. You will see updates on this in the coming weeks, but for the moment, we do not have a firm release date.

Hi, is there any news to report? It's been a couple of weeks since the last post ;)

We are pretty close to releasing this, please bear with us as we address some of the remaining rough edges.

Will this feature could be released before one year. Almost there

As of today, experimental multi-tab is available for you to play with. Please download Firebase Web 5.5.0 and enable multi-tab persistence as such:

db.enablePersistence({experimentalTabSynchronization: true})

Please do let us know if/what types of issues you encounter.

Was this page helpful?
0 / 5 - 0 ratings