diff --git a/synapse/metrics/background_process_metrics.py b/synapse/metrics/background_process_metrics.py
index 9ea4e23b31..f1f1f0cdf9 100644
--- a/synapse/metrics/background_process_metrics.py
+++ b/synapse/metrics/background_process_metrics.py
@@ -322,13 +322,21 @@ class BackgroundProcessLoggingContext(LoggingContext):
if instance_id is None:
instance_id = id(self)
super().__init__("%s-%s" % (name, instance_id))
- self._proc = _BackgroundProcess(name, self)
+ self._proc: Optional[_BackgroundProcess] = _BackgroundProcess(name, self)
def start(self, rusage: "Optional[resource.struct_rusage]") -> None:
"""Log context has started running (again)."""
super().start(rusage)
+ if self._proc is None:
+ logger.error(
+ "Background process re-entered without a proc: %s",
+ self.name,
+ stack_info=True,
+ )
+ return
+
# We've become active again so we make sure we're in the list of active
# procs. (Note that "start" here means we've become active, as opposed
# to starting for the first time.)
@@ -345,6 +353,14 @@ class BackgroundProcessLoggingContext(LoggingContext):
super().__exit__(type, value, traceback)
+ if self._proc is None:
+ logger.error(
+ "Background process exited without a proc: %s",
+ self.name,
+ stack_info=True,
+ )
+ return
+
# The background process has finished. We explicitly remove and manually
# update the metrics here so that if nothing is scraping metrics the set
# doesn't infinitely grow.
@@ -352,3 +368,6 @@ class BackgroundProcessLoggingContext(LoggingContext):
_background_processes_active_since_last_scrape.discard(self._proc)
self._proc.update_metrics()
+
+ # Set proc to None to break the reference cycle.
+ self._proc = None
|