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
Dexie.Observable: startObserving function: remove read-only query in order to avoid TransactionInactiveError #1138
Conversation
NB: This does pass existing tests (locally here, at least), but additional test coverage would be worthwhile to prove the fix and prevent regressions (assuming it's a reasonable/correct approach, which it may not be!) |
This reverts commit 1ec3e03.
…nsaction context when setting heartbeat, poll timeouts
…rent transaction context when setting heartbeat, poll timeouts" This reverts commit 5237d33.
pollHandle = setTimeout(poll, LOCAL_POLL); | ||
// Start heartbeat | ||
heartbeatHandle = setTimeout(heartbeat, HEARTBEAT_INTERVAL); | ||
db.transaction('rw!', '_syncNodes', () => { |
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 'works', but needs a bit of scrutiny as to whether it retains atomicity:
- https://dexie.org/docs/Dexie/Dexie.transaction()#specify-reusage-of-parent-transaction
- https://dexie.org/docs/Dexie/Dexie.transaction()#implementation-details-of-nested-transactions
Ideally some test coverage to check & prove atomicity would be nice.
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.
Another related thought: this is currently essentially performing a get-and-set within a transaction to ensure atomicity.
Would it be possible instead to use a single write operation (Table.modify
or similar) to perform the required updates?
That way there would be no read-only query required within the transaction, and the transaction would not risk becoming inactive as a result of that query completing before any writes occur.
Our requirements are to:
- Set the current node's
isMaster
flag when no record withisMaster
and an up-to-date heartbeat timestamp is present - Unset the
isMaster
flag on a record if the heartbeat timestamp is out-of-date - Write the current node record into the table
The challenge is that the value we write for the current node record depends on the contents of a potentially existing (or potentially nonexistent) record with isMaster
set and potentially out-of-date heartbeat timestamp.
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.
It does look like the isMaster
field is an indexable type (ref: definition as Number
), so perhaps it would be possible to use db._syncNodes.orderBy(...).modify(...)
to retrieve existing syncnodes in order, maintain an external variable to store the 'current node should become master' state, and then use a function argument to modify to write the expected object record(s).
… node status during initialization
…o database record
@dfahlander Apologies for any notification noise from this and the associated issue over the past few days; it's taken a while to work out what's been going on, and attempt different approaches to a solution :) I think this is ready for another look now; I'm becoming more confident in the correctness of this after understanding the purpose of the code a little better, and given the test coverage in Dexie itself and also when using it alongside the dexie-1126-repro example case. |
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 for the deep dive in this issue and for finding a solution.
No problem, thanks! |
The cause of #1126 seems to relate to conflict between the (re)use of transactions on the
_syncNodes
Dexie-internal table after theready
trigger fires but before the database has completed opening.The attempted fix here replaces two separate read & then write operations with a single-pass
modify
operation over thedb._syncNodes
internal table -- relying onTable.orderBy
to ensure that existing master sync node state is assessed before the 'local' sync node record is updated -- within aDexie.ignoreTransaction
-- to retain atomicity, while avoiding re-use of the 'current' transaction.Resolves #1126