diff --git a/src/tribler/core/components/ipv8/ipv8_component.py b/src/tribler/core/components/ipv8/ipv8_component.py index cf8ecddc0aa..786cbc421c7 100644 --- a/src/tribler/core/components/ipv8/ipv8_component.py +++ b/src/tribler/core/components/ipv8/ipv8_component.py @@ -66,11 +66,6 @@ async def run(self): key_component = await self.require_component(KeyComponent) self.peer = Peer(key_component.primary_key) - if config.ipv8.statistics and not config.gui_test_mode: - # Enable gathering IPv8 statistics - for overlay in ipv8.overlays: - ipv8.endpoint.enable_community_statistics(overlay.get_prefix(), True) - if config.ipv8.walk_scaling_enabled and not config.gui_test_mode: from tribler.core.components.ipv8.ipv8_health_monitor import IPv8Monitor IPv8Monitor(ipv8, @@ -87,6 +82,19 @@ async def run(self): if config.dht.enabled: self.dht_discovery_community.routing_tables[UDPv4Address] = RoutingTable('\x00' * 20) + def start_statistics_for_registered_overlays(self): + """ + Enable gathering IPv8 statistics for all currently registered overlays. + The caller must ensure that config.ipv8.statistics is enabled and config.gui_test_mode is not enabled. + + Because Tribler chooses to inject overlays at runtime, this method must be called after all other components + have injected their communities. If the components are ever refactored to use launch their Community instances + though IPv8's constructor, this functionality can be moved back into ``run()``. + More information: https://github.com/Tribler/tribler/issues/7552 + """ + for overlay in self.ipv8.overlays: + self.ipv8.endpoint.enable_community_statistics(overlay.get_prefix(), True) + def initialise_community_by_default(self, community, default_random_walk_max_peers=20): community.bootstrappers.append(self.make_bootstrapper()) diff --git a/src/tribler/core/components/session.py b/src/tribler/core/components/session.py index d3c8973b9fd..c188b9b51e8 100644 --- a/src/tribler/core/components/session.py +++ b/src/tribler/core/components/session.py @@ -10,6 +10,7 @@ from tribler.core.components.component import Component from tribler.core.components.exceptions import ComponentError, ComponentStartupException, MultipleComponentsFound +from tribler.core.components.ipv8.ipv8_component import Ipv8Component from tribler.core.components.reporter.exception_handler import default_core_exception_handler from tribler.core.config.tribler_config import TriblerConfig from tribler.core.sentry_reporter.sentry_reporter import SentryReporter @@ -79,6 +80,11 @@ def register(self, comp_cls: Type[Component], component: Component): self.components[comp_cls] = component component.session = self + def _post_start(self): + # The following must be called after all other components have finished injecting their ``Community`` instances. + if self.config.ipv8.enabled and self.config.ipv8.statistics and not self.config.gui_test_mode: + self.get_instance(Ipv8Component).start_statistics_for_registered_overlays() + async def start_components(self): t = time.time() self.logger.info('Starting components...') @@ -92,6 +98,9 @@ async def start_components(self): coros = [comp.start() for comp in self.components.values()] await gather(*coros, return_exceptions=not self.failfast) + + self._post_start() + duration = time.time() - t if e := self._startup_exception: self.logger.warning(f'Components started in {duration:.3f} seconds with exception: {type(e).__name__}: {e}')