diff options
author | Mark Haines <mjark@negativecurvature.net> | 2015-10-13 18:40:57 +0100 |
---|---|---|
committer | Mark Haines <mjark@negativecurvature.net> | 2015-10-13 18:40:57 +0100 |
commit | 474274583f664cf3184958bff829d7b50224c9a6 (patch) | |
tree | 1185679c0a23bd6f7b25c19ef1b0f873dc1be756 /synapse/util | |
parent | Merge pull request #301 from matrix-org/markjh/v2_filtering (diff) | |
parent | Enable stack traces for the demo scripts (diff) | |
download | synapse-474274583f664cf3184958bff829d7b50224c9a6.tar.xz |
Merge pull request #303 from matrix-org/markjh/twisted_debugging
Bounce all deferreds through the reactor to make debugging easier.
Diffstat (limited to 'synapse/util')
-rw-r--r-- | synapse/util/debug.py | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/synapse/util/debug.py b/synapse/util/debug.py new file mode 100644 index 0000000000..f6a5a841a4 --- /dev/null +++ b/synapse/util/debug.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# Copyright 2015 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from twisted.internet import defer, reactor +from functools import wraps +from synapse.util.logcontext import LoggingContext, PreserveLoggingContext + + +def debug_deferreds(): + """Cause all deferreds to wait for a reactor tick before running their + callbacks. This increases the chance of getting a stack trace out of + a defer.inlineCallback since the code waiting on the deferred will get + a chance to add an errback before the deferred runs.""" + + # Helper method for retrieving and restoring the current logging context + # around a callback. + def with_logging_context(fn): + context = LoggingContext.current_context() + + def restore_context_callback(x): + with PreserveLoggingContext(): + LoggingContext.thread_local.current_context = context + return fn(x) + + return restore_context_callback + + # We are going to modify the __init__ method of defer.Deferred so we + # need to get a copy of the old method so we can still call it. + old__init__ = defer.Deferred.__init__ + + # We need to create a deferred to bounce the callbacks through the reactor + # but we don't want to add a callback when we create that deferred so we + # we create a new type of deferred that uses the old __init__ method. + # This is safe as long as the old __init__ method doesn't invoke an + # __init__ using super. + class Bouncer(defer.Deferred): + __init__ = old__init__ + + # We'll add this as a callback to all Deferreds. Twisted will wait until + # the bouncer deferred resolves before calling the callbacks of the + # original deferred. + def bounce_callback(x): + bouncer = Bouncer() + reactor.callLater(0, with_logging_context(bouncer.callback), x) + return bouncer + + # We'll add this as an errback to all Deferreds. Twisted will wait until + # the bouncer deferred resolves before calling the errbacks of the + # original deferred. + def bounce_errback(x): + bouncer = Bouncer() + reactor.callLater(0, with_logging_context(bouncer.errback), x) + return bouncer + + @wraps(old__init__) + def new__init__(self, *args, **kargs): + old__init__(self, *args, **kargs) + self.addCallbacks(bounce_callback, bounce_errback) + + defer.Deferred.__init__ = new__init__ |