Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Make make_deferred_yieldable re-entrant.
Browse files Browse the repository at this point in the history
This then lets us use it on deferreds/functions that may or may not
already follow the log context rules.
  • Loading branch information
erikjohnston committed Aug 8, 2019
1 parent c0f3555 commit 88d5b5e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
16 changes: 13 additions & 3 deletions synapse/logging/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,20 @@ def make_deferred_yieldable(deferred):
# immediately. We may as well optimise out the logcontext faffery.
return deferred

# ok, we can't be sure that a yield won't block, so let's reset the
if LoggingContext.current_context() is LoggingContext.sentinel:
# We're already in the sentinel context, so there's nothing to do. If we
# did attempt to "restore" the log context then we could easily clobber
# another log context that had been saved during the generation of this
# deferred.
# This makes it safe to call `make_deferred_yieldable` on deferreds that
# already have set the log contexts.
return deferred

# Ok, we can't be sure that a yield won't block, so let's reset the
# logcontext, and add a callback to the deferred to restore it.
prev_context = LoggingContext.set_current_context(LoggingContext.sentinel)
deferred.addBoth(_set_context_cb, prev_context)
if LoggingContext.current_context() is not LoggingContext.sentinel:
prev_context = LoggingContext.set_current_context(LoggingContext.sentinel)
deferred.addBoth(_set_context_cb, prev_context)
return deferred


Expand Down
23 changes: 23 additions & 0 deletions tests/util/test_logcontext.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,29 @@ def test_make_deferred_yieldable_on_non_deferred(self):
self.assertEqual(r, "bum")
self._check_test_key("one")

@defer.inlineCallbacks
def test_make_deferred_yieldable_reentrant(self):
"""Test that `make_deferred_yieldable` does the right thing on deferreds
that already follow log context rules, i.e. wrapping a deferred with
`make_deferred_yieldable` multiple times.
"""

sentinel_context = LoggingContext.current_context()

with LoggingContext() as context_one:
context_one.request = "one"

d1 = make_deferred_yieldable(_chained_deferred_function())
d2 = make_deferred_yieldable(d1)

# make sure that the context was reset by make_deferred_yieldable
self.assertIs(LoggingContext.current_context(), sentinel_context)

yield d2

# now it should be restored
self._check_test_key("one")

def test_nested_logging_context(self):
with LoggingContext(request="foo"):
nested_context = nested_logging_context(suffix="bar")
Expand Down

0 comments on commit 88d5b5e

Please sign in to comment.