Skip to content

Commit ca655e4

Browse files
Start background tasks after we fork the process (daemonize) (#18886)
Spawning from #18871 [This change](6ce2f3e) was originally used to fix CPU time going backwards when we `daemonize`. While, we don't seem to run into this problem on `develop`, I still think this is a good change to make. We don't need background tasks running on a process that will soon be forcefully exited and where the reactor isn't even running yet. We now kick off the background tasks (`run_as_background_process`) after we have forked the process and started the reactor. Also as simple note, we don't need background tasks running in both halves of a fork.
1 parent 7951d41 commit ca655e4

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

changelog.d/18886.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Start background tasks after we fork the process (daemonize).

synapse/_scripts/update_synapse_database.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ def main() -> None:
120120
# DB.
121121
hs.setup()
122122

123+
# This will cause all of the relevant storage classes to be instantiated and call
124+
# `register_background_update_handler(...)`,
125+
# `register_background_index_update(...)`,
126+
# `register_background_validate_constraint(...)`, etc so they are available to use
127+
# if we are asked to run those background updates.
128+
hs.get_storage_controllers()
129+
123130
if args.run_background_updates:
124131
run_background_updates(hs)
125132

synapse/app/_base.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,10 +609,28 @@ def run_sighup(*args: Any, **kwargs: Any) -> None:
609609
setup_sentry(hs)
610610
setup_sdnotify(hs)
611611

612-
# If background tasks are running on the main process or this is the worker in
613-
# charge of them, start collecting the phone home stats and shared usage metrics.
612+
# Register background tasks required by this server. This must be done
613+
# somewhat manually due to the background tasks not being registered
614+
# unless handlers are instantiated.
615+
#
616+
# While we could "start" these before the reactor runs, nothing will happen until
617+
# the reactor is running, so we may as well do it here in `start`.
618+
#
619+
# Additionally, this means we also start them after we daemonize and fork the
620+
# process which means we can avoid any potential problems with cputime metrics
621+
# getting confused about the per-thread resource usage appearing to go backwards
622+
# because we're comparing the resource usage (`rusage`) from the original process to
623+
# the forked process.
614624
if hs.config.worker.run_background_tasks:
625+
hs.start_background_tasks()
626+
627+
# TODO: This should be moved to same pattern we use for other background tasks:
628+
# Add to `REQUIRED_ON_BACKGROUND_TASK_STARTUP` and rely on
629+
# `start_background_tasks` to start it.
615630
await hs.get_common_usage_metrics_manager().setup()
631+
632+
# TODO: This feels like another pattern that should refactored as one of the
633+
# `REQUIRED_ON_BACKGROUND_TASK_STARTUP`
616634
start_phone_stats_home(hs)
617635

618636
# We now freeze all allocated objects in the hopes that (almost)

synapse/server.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -366,12 +366,6 @@ def setup(self) -> None:
366366
self.datastores = Databases(self.DATASTORE_CLASS, self)
367367
logger.info("Finished setting up.")
368368

369-
# Register background tasks required by this server. This must be done
370-
# somewhat manually due to the background tasks not being registered
371-
# unless handlers are instantiated.
372-
if self.config.worker.run_background_tasks:
373-
self.setup_background_tasks()
374-
375369
def __del__(self) -> None:
376370
"""
377371
Called when an the homeserver is garbage collected.
@@ -410,7 +404,7 @@ def start_listening(self) -> None: # noqa: B027 (no-op by design)
410404
appropriate listeners.
411405
"""
412406

413-
def setup_background_tasks(self) -> None:
407+
def start_background_tasks(self) -> None:
414408
"""
415409
Some handlers have side effects on instantiation (like registering
416410
background updates). This function causes them to be fetched, and

tests/server.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,16 @@ def setup_test_homeserver(
11601160
with patch("synapse.storage.database.make_pool", side_effect=make_fake_db_pool):
11611161
hs.setup()
11621162

1163+
# Register background tasks required by this server. This must be done
1164+
# somewhat manually due to the background tasks not being registered
1165+
# unless handlers are instantiated.
1166+
#
1167+
# Since, we don't have to worry about `daemonize` (forking the process) in tests, we
1168+
# can just start the background tasks straight away after `hs.setup`. (compare this
1169+
# with where we call `hs.start_background_tasks()` outside of the test environment).
1170+
if hs.config.worker.run_background_tasks:
1171+
hs.start_background_tasks()
1172+
11631173
# Since we've changed the databases to run DB transactions on the same
11641174
# thread, we need to stop the event fetcher hogging that one thread.
11651175
hs.get_datastores().main.USE_DEDICATED_DB_THREADS_FOR_EVENT_FETCHING = False

0 commit comments

Comments
 (0)