diff options
author | Sean Quah <8349537+squahtx@users.noreply.github.com> | 2022-03-14 19:04:29 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-14 19:04:29 +0000 |
commit | 2fcf4b3f6cd2a0be6597622664636d2219957c2a (patch) | |
tree | 3b483383273873a6d5934fed6ad1fa4cb102cfeb /synapse/util/caches | |
parent | Add cancellation support to `ReadWriteLock` (#12120) (diff) | |
download | synapse-2fcf4b3f6cd2a0be6597622664636d2219957c2a.tar.xz |
Add cancellation support to `@cached` and `@cachedList` decorators (#12183)
These decorators mostly support cancellation already. Add cancellation tests and fix use of finished logging contexts by delaying cancellation, as suggested by @erikjohnston. Signed-off-by: Sean Quah <seanq@element.io>
Diffstat (limited to 'synapse/util/caches')
-rw-r--r-- | synapse/util/caches/descriptors.py | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/synapse/util/caches/descriptors.py b/synapse/util/caches/descriptors.py index c3c5c16db9..eda92d864d 100644 --- a/synapse/util/caches/descriptors.py +++ b/synapse/util/caches/descriptors.py @@ -41,6 +41,7 @@ from twisted.python.failure import Failure from synapse.logging.context import make_deferred_yieldable, preserve_fn from synapse.util import unwrapFirstError +from synapse.util.async_helpers import delay_cancellation from synapse.util.caches.deferred_cache import DeferredCache from synapse.util.caches.lrucache import LruCache @@ -350,6 +351,11 @@ class DeferredCacheDescriptor(_CacheDescriptorBase): ret = defer.maybeDeferred(preserve_fn(self.orig), obj, *args, **kwargs) ret = cache.set(cache_key, ret, callback=invalidate_callback) + # We started a new call to `self.orig`, so we must always wait for it to + # complete. Otherwise we might mark our current logging context as + # finished while `self.orig` is still using it in the background. + ret = delay_cancellation(ret) + return make_deferred_yieldable(ret) wrapped = cast(_CachedFunction, _wrapped) @@ -510,6 +516,11 @@ class DeferredCacheListDescriptor(_CacheDescriptorBase): d = defer.gatherResults(cached_defers, consumeErrors=True).addCallbacks( lambda _: results, unwrapFirstError ) + if missing: + # We started a new call to `self.orig`, so we must always wait for it to + # complete. Otherwise we might mark our current logging context as + # finished while `self.orig` is still using it in the background. + d = delay_cancellation(d) return make_deferred_yieldable(d) else: return defer.succeed(results) |