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

IDB transaction before store is created #182

Open
jamime opened this issue May 17, 2016 · 3 comments
Open

IDB transaction before store is created #182

jamime opened this issue May 17, 2016 · 3 comments

Comments

@jamime
Copy link

jamime commented May 17, 2016

When creating a IDB store for the first time if we attempt to perform an operation on the store _getTransaction fails.

We currently check for if (!this.db) to see if the store has been created. However, this.db could also be an unresolved promise if the open request has not yet completed (i.e. upgrade is still in progress). We don't currently accommodate for this.

this.db should only reference the IDB when it is fully ready to be interacted with, and _getTransaction should be checking to see if it is a promise, if it is it should chain the request so it is fired once the open request completes.

IndexedDB.js:169 Uncaught InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running.
@jamime
Copy link
Author

jamime commented May 17, 2016

Actually, _callOnStore handles this logic. So the real issue is that the open promise is resolving whilst an upgrade is happening.

...

Which I believe is handled by makePromise which makes my wonder why I'm receiving this exception in the first place. Any ideas?

@jamime
Copy link
Author

jamime commented May 27, 2016

I've investigated this further.

/**
             * This works around various browser inconsistencies dealing with microtasks, queues and schedules.
             * IndexedDB runs in its own 'thread' and therefore has its own event loop. This means if we were to do
             * something blocking in the main thread IndexedDB would continue to process its own tasks.
             *
             * IndexedDB fires an onsuccess event which DStore converts to be promise-like. It appears that step 4 of
             * the onsuccess event sometimes happens before the promise resolves and sometimes after
             * (http://w3c.github.io/IndexedDB/#fire-a-success-event). When the transaction has not been set as inactive
             * creating a new transaction will fail.
             *
             * To work around this, when we fail to create a new transaction, we catch the exception and retry
             * asynchronously. This allows the rest of the application to continue and won't block user interaction.
**/

I've achieved this by using try/catch and setTimeout(fn, 0). I retry an unlimited number of times (maximum call stack size exceeded occurs). Typically I only get one or two retries.

This issue only occurs when onupgradedneeded fires (so a version change or creating a DB for the first time).

Side note, re-assigning db makes this type of bug very hard to investigate.

@lzhoucs
Copy link
Contributor

lzhoucs commented Oct 28, 2016

I couldn't reproduce this issue on my chrome(54.0.2840.59) and FF(49.0.2).

When opening a connection request, success event won't be fired until onupgradeneeded callback is done. And by the time onsuccesscallback is called, the transaction should have been set to inactive, and the promise is resolved after onsuccess callback is called. So technically the scenario you mentioned should never happen.

If you can provide more information such as which browser were you using, along with some sample code, it would help us further investigate the issue, since there could be an issue with a specific browser IDB implementation that have caused it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants