-
Hi! Appreciate the package! (Tested on android, drift 2.10.0 with isolates enabled) I am encountering "Transaction used after it was closed" assertion error. What happens is that I launch asynchronous/delayed interaction with DB inside of a transaction. Following pseudo example illustrates the issue:
So the question is:
PS. I know transaction doc says that you have to await all calls, but I didn't think it was that extreme :) Can someone elaborate on whats happening? Thanks in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
The intended behavior is that, after the
Indeed, drift uses zones to bind the transaction callback (and all the asynchronous calls that it will make it turn) to the transaction. To answer your questions,
I think your queries would softlock without the assertion. Drift runs the database in another thread (if you're using
I think the easiest solution would be to literally move the timer setup outside of the transaction, e.g. by starting the timer before or after the transaction.
This is a bit hacky, but also works if moving the timer outside of the transaction block is not easily possible: // Call this outside of the transaction to get a callback capable of running code outside
// of the transaction context.
final escapeHatch =
Zone.current.bindUnaryCallback((void Function() argument) => argument());
await db.transaction(() async {
await select(some).get();
escapeHatch(() {
Timer.periodic(const Duration(seconds: 10), (timer) async {
await select(some).get();
});
});
await Future.delayed(const Duration(seconds: 5));
}); With this setup, note that queries in the timer can't run if the transaction is still active (so if the transaction takes more than 10 seconds to complete, the first timer query will be delayed). |
Beta Was this translation helpful? Give feedback.
-
Many thanks for giving me understanding on whats going on with Zones! I see them mentioned several times in code docs but mb it makes sence to make more emphasis on it in transaction docs for guys like me ^^? Decided to refactor code to not run async updates inside of a transaction, but really like your "hack". Marking as resolved. Thanks again! |
Beta Was this translation helpful? Give feedback.
The intended behavior is that, after the
transaction
block completes, the logical transaction is ending as well. Drift goes quite a length to achieve that (for instance, streams watching a drift query in a transaction will also close their listeners afterwards). We need to do that because transactions need an explicitCOMMIT
statement, and we can't know that your timer action is read-only (if it weren't, should it implicitly run outside of the transaction? that can lead to some hard-to-debug correctness issues for the more common case where you simply forgot an await). So tldr, everything happening in atransaction
block needs to be done accessing the database when it completes.