-
Notifications
You must be signed in to change notification settings - Fork 934
Make 'handleClientStateEvent()/handleQueryTargetEvent()' idempotent #2916
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ describeSpec( | |
// Client 1 has received the WebStorage notification that the write | ||
// has been acknowledged, but failed to process the change. Hence, | ||
// we did not get a user callback. We schedule the first retry and | ||
// make sure that it also does not get processed until | ||
// make sure that it also does not get processed until | ||
// `recoverDatabase` is called. | ||
.runTimer(TimerId.AsyncQueueRetry) | ||
.recoverDatabase() | ||
|
@@ -55,7 +55,7 @@ describeSpec( | |
); | ||
|
||
specTest( | ||
'Query raises events in secondary client (with recovery)', | ||
'Query raises events in secondary client (with recovery)', | ||
['multi-client'], | ||
() => { | ||
const query = Query.atPath(path('collection')); | ||
|
@@ -75,5 +75,38 @@ describeSpec( | |
.expectEvents(query, {}); | ||
} | ||
); | ||
|
||
specTest( | ||
'Query is listened to by primary (with recovery)', | ||
['multi-client'], | ||
() => { | ||
const query = Query.atPath(path('collection')); | ||
|
||
return ( | ||
client(0) | ||
.expectPrimaryState(true) | ||
.failDatabase() | ||
.client(1) | ||
.userListens(query) | ||
.client(0) | ||
// The primary client 0 receives a WebStorage notification about the | ||
// new query, but it cannot load the target from IndexedDB. The | ||
// query will only be listened to once we recover the database. | ||
.recoverDatabase() | ||
.runTimer(TimerId.AsyncQueueRetry) | ||
.expectListen(query) | ||
.failDatabase() | ||
.client(1) | ||
.userUnlistens(query) | ||
.client(0) | ||
// The primary client 0 receives a notification that the query can | ||
// be released, but it can only process the change after we recover | ||
// the database. | ||
.recoverDatabase() | ||
.runTimer(TimerId.AsyncQueueRetry) | ||
.expectActiveTargets() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we expect that there is an active target before recoverDatabase? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The targets are checked at each step, but adding this here explicitly makes it much clearer what is going on. Done. |
||
); | ||
} | ||
); | ||
} | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would this happen in practice that isn't a bug? I mean, how could we get in a state where the sync engine thought we were listening but local store didn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to guard against this line: https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/core/sync_engine.ts#L1115
I did miss that this is only executed if the target is still active. I reverted this change.