-
Notifications
You must be signed in to change notification settings - Fork 928
Provide warning and potential workaround for iOS Safari bug described by #1670. #1854
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
Conversation
… by #1670. * On iOS 12.2 we proactively warn about the "internal error was encountered in Indexed Database Server" Bug. * When the bug is actually encountered on iOS >= 12.2 an < 13 we log a custom error message. Both log message and error link to https://stackoverflow.com/q/56496296/110915 which provides potential error handling / recovery example.
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.
Some suggestions for you :)
@@ -15,9 +15,10 @@ | |||
* limitations under the License. | |||
*/ | |||
|
|||
import { getUA } from '@firebase/util'; |
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 take it we don't have API reviews for @firebase/util
? :)
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.
The @firebase/*
packages are technically considered internal and aren't meant for public consumption. 🤷♂
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.
We should use Go-style variable names everywhere :)
.split('_') | ||
.slice(0, 2) | ||
.join('.') | ||
: '-1'; | ||
return Number(version); |
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.
My gut feeling is that version numbers are better represented as strings.
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.
Yeah, potentially... though strings don't necessarily compare properly. In any case, all I did is make getIOSVersion() match the existing getAndroidVersion() function, so I'm inclined to keep it for now.
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.
Sounds good. Will bug you about it again when we need to block 12.3.1.
@@ -578,7 +599,9 @@ export class SimpleDbStore< | |||
const cursorRequest = this.cursor({}); | |||
return new PersistencePromise((resolve, reject) => { | |||
cursorRequest.onerror = (event: Event) => { | |||
reject((event.target as IDBRequest).error!); | |||
const error = (event.target as IDBRequest).error!; |
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.
You could move this cast into checkForAndReportiOSError
, which could then do an instanceof
check..
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.
we need the cast result for reject(error)
too though... and IDBRequest is an interface not a class, so no instanceof checks. :-/
return; | ||
} | ||
const iOSVersion = SimpleDb.getIOSVersion(getUA()); | ||
if (iOSVersion >= 12.2 && iOSVersion < 13) { |
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.
- Now I understand why we use a version number and not a version number string.
- Do we need to guard this check on the iOS version? We might just want to log the console message whenever we encounter the matching error string.
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.
Given the iOS error message is so generic, I am a little worried about making this check too open-ended and possibly having it hide future bugs in iOS Safari's IndexedDB implementation (I also named this "IOS_INDEXEDDB_BUG1" to allow for future bugs in the future 😛)... So I prefer keeping the version scoped for now.
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.
Sounds good. Glad you didn't use IOS_INDEXEDDB_BUG_001 :)
reportedIOSError = true; | ||
// Throw a global exception outside of this promise chain, for the user to | ||
// potentially catch. | ||
setTimeout(() => { |
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.
This could be setImmediate
.
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.
https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
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.
Hm. I learned something today.
(Never develop JS for browsers).
setTimeout(() => { | ||
throw new FirestoreError( | ||
'internal', | ||
`IOS_INDEXEDDB_BUG1: IndexedDb has thrown '${IOS_ERROR}'. This is likely ` + |
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.
Is IOS_INDEXEDDB_BUG1
intentional?
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.
Yup. Future proofing for the next iOS bug that bites us. 😬
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.
Thanks! PTAL
@@ -15,9 +15,10 @@ | |||
* limitations under the License. | |||
*/ | |||
|
|||
import { getUA } from '@firebase/util'; |
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.
The @firebase/*
packages are technically considered internal and aren't meant for public consumption. 🤷♂
.split('_') | ||
.slice(0, 2) | ||
.join('.') | ||
: '-1'; | ||
return Number(version); |
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.
Yeah, potentially... though strings don't necessarily compare properly. In any case, all I did is make getIOSVersion() match the existing getAndroidVersion() function, so I'm inclined to keep it for now.
@@ -578,7 +599,9 @@ export class SimpleDbStore< | |||
const cursorRequest = this.cursor({}); | |||
return new PersistencePromise((resolve, reject) => { | |||
cursorRequest.onerror = (event: Event) => { | |||
reject((event.target as IDBRequest).error!); | |||
const error = (event.target as IDBRequest).error!; |
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.
we need the cast result for reject(error)
too though... and IDBRequest is an interface not a class, so no instanceof checks. :-/
return; | ||
} | ||
const iOSVersion = SimpleDb.getIOSVersion(getUA()); | ||
if (iOSVersion >= 12.2 && iOSVersion < 13) { |
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.
Given the iOS error message is so generic, I am a little worried about making this check too open-ended and possibly having it hide future bugs in iOS Safari's IndexedDB implementation (I also named this "IOS_INDEXEDDB_BUG1" to allow for future bugs in the future 😛)... So I prefer keeping the version scoped for now.
reportedIOSError = true; | ||
// Throw a global exception outside of this promise chain, for the user to | ||
// potentially catch. | ||
setTimeout(() => { |
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.
https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
setTimeout(() => { | ||
throw new FirestoreError( | ||
'internal', | ||
`IOS_INDEXEDDB_BUG1: IndexedDb has thrown '${IOS_ERROR}'. This is likely ` + |
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.
Yup. Future proofing for the next iOS bug that bites us. 😬
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.
Ship it.
@@ -15,9 +15,10 @@ | |||
* limitations under the License. | |||
*/ | |||
|
|||
import { getUA } from '@firebase/util'; |
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.
We should use Go-style variable names everywhere :)
.split('_') | ||
.slice(0, 2) | ||
.join('.') | ||
: '-1'; | ||
return Number(version); |
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.
Sounds good. Will bug you about it again when we need to block 12.3.1.
return; | ||
} | ||
const iOSVersion = SimpleDb.getIOSVersion(getUA()); | ||
if (iOSVersion >= 12.2 && iOSVersion < 13) { |
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.
Sounds good. Glad you didn't use IOS_INDEXEDDB_BUG_001 :)
reportedIOSError = true; | ||
// Throw a global exception outside of this promise chain, for the user to | ||
// potentially catch. | ||
setTimeout(() => { |
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.
Hm. I learned something today.
(Never develop JS for browsers).
Indexed Database Server" Bug.
error message.
Both log message and error link to https://stackoverflow.com/q/56496296/110915 which
provides potential error handling / recovery example.