@@ -230,6 +230,11 @@ def run_as_background_process(
230230 clock.looping_call and friends (or for firing-and-forgetting in the middle of a
231231 normal synapse async function).
232232
233+ Because the returned Deferred does not follow the synapse logcontext rules, awaiting
234+ the result of this function will result in the log context being cleared. In order
235+ to properly await the result of this function and maintain the current log context,
236+ use `make_deferred_yieldable`.
237+
233238 Args:
234239 desc: a description for this background process type
235240 server_name: The homeserver name that this background process is being run for
@@ -285,7 +290,20 @@ async def run() -> Optional[R]:
285290 name = desc , ** {SERVER_NAME_LABEL : server_name }
286291 ).dec ()
287292
293+ # To explain how the log contexts work here:
294+ # - When this function is called, the current context is stored (using
295+ # `PreserveLoggingContext`), we kick off the background task, and we restore the
296+ # original context before returning (also part of `PreserveLoggingContext`).
297+ # - When the background task finishes, we don't want to leak our background context
298+ # into the reactor which would erroneously get attached to the next operation
299+ # picked up by the event loop. We use `PreserveLoggingContext` to set the
300+ # `sentinel` context and means the new `BackgroundProcessLoggingContext` will
301+ # remember the `sentinel` context as its previous context to return to when it
302+ # exits and yields control back to the reactor.
288303 with PreserveLoggingContext ():
304+ # The async `run` task is wrapped in a deferred, which will have the side effect
305+ # of executing the coroutine.
306+ #
289307 # Note that we return a Deferred here so that it can be used in a
290308 # looping_call and other places that expect a Deferred.
291309 return defer .ensureDeferred (run ())
0 commit comments