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

Commit

Permalink
Fix 'Unhandled error in Deferred'
Browse files Browse the repository at this point in the history
Fixes a CRITICAL "Unhandled error in Deferred" log message which happened when
a function wrapped with `@cachedList` failed
  • Loading branch information
richvdh committed Feb 25, 2022
1 parent b43c3ef commit a7d83d3
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 17 deletions.
1 change: 1 addition & 0 deletions changelog.d/12089.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix occasional 'Unhandled error in Deferred' error message.
31 changes: 14 additions & 17 deletions synapse/util/caches/descriptors.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ def arg_to_cache_key(arg: Hashable) -> Hashable:
deferred: "defer.Deferred[Any]" = defer.Deferred()
deferreds_map[arg] = deferred
key = arg_to_cache_key(arg)
cache.set(key, deferred, callback=invalidate_callback)
cached_defers.append(
cache.set(key, deferred, callback=invalidate_callback)
)

def complete_all(res: Dict[Hashable, Any]) -> None:
# the wrapped function has completed. It returns a
Expand All @@ -455,28 +457,23 @@ def complete_all(res: Dict[Hashable, Any]) -> None:
deferreds_map[e].callback(val)
results[e] = val

def errback(f: Failure) -> Failure:
# the wrapped function has failed. Invalidate any cache
# entries we're supposed to be populating, and fail
# their deferreds.
for e in missing:
key = arg_to_cache_key(e)
cache.invalidate(key)
deferreds_map[e].errback(f)

# return the failure, to propagate to our caller.
return f
def errback_all(f: Failure) -> None:
# the wrapped function has failed. Propagate the failure into
# the cache, which will invalidate the entry, and cause the
# relevant cached_deferreds to fail, which will propagate the
# failure to our caller.
for d1 in deferreds_map.values():
d1.errback(f)

args_to_call = dict(arg_dict)
# copy the missing set before sending it to the callee, to guard against
# modification.
args_to_call[self.list_name] = tuple(missing)

cached_defers.append(
defer.maybeDeferred(
preserve_fn(self.orig), **args_to_call
).addCallbacks(complete_all, errback)
)
# dispatch the call, and attach the two handlers
defer.maybeDeferred(
preserve_fn(self.orig), **args_to_call
).addCallbacks(complete_all, errback_all)

if cached_defers:
d = defer.gatherResults(cached_defers, consumeErrors=True).addCallbacks(
Expand Down

0 comments on commit a7d83d3

Please sign in to comment.