-
Notifications
You must be signed in to change notification settings - Fork 67
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
fix: refactor transactions to use their own event loops #443
Conversation
Referring to issue googleapis#426, the problem ultimately turned out to be that we could fall out of the transaction scope and trigger a commit while there is still work left queued on the event loop, including, in this case, the tasklet that would eventually schedule the call to delete, causing the delete to never actually happen. The fix is to go ahead and consume the event loop queues before scheduling the call to COMMIT. However, if there are other tasks happening in parallel, this can really mess with the natural sequence of events in ways that can cause things to blow up. (All of the `parallel_transaction` tests in `tests/system/test_misc.py` for instance, will fail.) The fix for that is to give each transaction its own event loop, so that when it calls `_eventloop.run` prior to commit, it is only flushing tasks that pertain to it. Fixes googleapis#426
Following up on the main commit message, the move to separate event loops for transactions is not without its own complications. Sometimes flow of control will get passed back to the main loop before the transaction callback, if it is a tasklet, has finished. In this case, the main loop needs to be able to poke the inner loops to keep doing work until they've finished. This is handled by adding an idle handler to the main loop, There is also a minor change in the way we're handling deciding whether to call |
@@ -396,13 +395,7 @@ def run(): | |||
loop.run() | |||
|
|||
|
|||
def run0(): |
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.
Wasn't used.
@@ -123,7 +123,10 @@ def wait(self): | |||
after a call to this method. | |||
""" | |||
while not self._done: | |||
_eventloop.run1() | |||
if not _eventloop.run1(): |
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.
Sanity 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.
Wow, this took time to parse. Looks great.
Pretty much took all week to figure out! Thanks! |
Referring to issue #426, the problem ultimately turned out to be that
we could fall out of the transaction scope and trigger a commit while
there is still work left queued on the event loop, including, in this
case, the tasklet that would eventually schedule the call to delete,
causing the delete to never actually happen.
The fix is to go ahead and consume the event loop queues before
scheduling the call to COMMIT. However, if there are other tasks
happening in parallel, this can really mess with the natural sequence of
events in ways that can cause things to blow up. (All of the
parallel_transaction
tests intests/system/test_misc.py
forinstance, will fail.) The fix for that is to give each transaction its
own event loop, so that when it calls
_eventloop.run
prior to commit,it is only flushing tasks that pertain to it.
Fixes #426