From 364f365bc7f61b2697ce8d66e1cbad804984d2aa Mon Sep 17 00:00:00 2001 From: Goffi Date: Wed, 11 Mar 2026 10:58:24 +0100 Subject: [PATCH] core (launcher): set AsyncIO reactor in launcher The reactor is now set in the launcher, as it is the first script to be loaded. This should avoid race conditions when some Twisted or libervia packages are imported and end up importing `twisted.internet.reactor`, which installs the default reactor before the AsyncIO one. The AsyncIO reactor is still set in `twisted.plugin.libervia_backend_plugin` (but it no longer fails if already set), in case the backend is started as a plugin (although this is not recommended anyway) --- libervia/backend/core/launcher.py | 11 +++++++++-- twisted/plugins/libervia_backend_plugin.py | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libervia/backend/core/launcher.py b/libervia/backend/core/launcher.py index 7bb2f6d1..4dfc69ec 100644 --- a/libervia/backend/core/launcher.py +++ b/libervia/backend/core/launcher.py @@ -22,10 +22,17 @@ import sys import os import argparse from pathlib import Path -from twisted.application import app -from twisted.python import usage + +# We want to install asyncreactor before any import from twisted or Libervia to be sure +# that the right reactor is used. +from twisted.internet import asyncioreactor + +asyncioreactor.install() + from libervia.backend.core.constants import Const as C from libervia.backend.tools.config import parse_main_conf +from twisted.application import app +from twisted.python import usage class LiberviaLogger(app.AppLogger): diff --git a/twisted/plugins/libervia_backend_plugin.py b/twisted/plugins/libervia_backend_plugin.py index b6aae162..1e69d87c 100644 --- a/twisted/plugins/libervia_backend_plugin.py +++ b/twisted/plugins/libervia_backend_plugin.py @@ -17,12 +17,14 @@ # along with this program. If not, see . +from twisted.internet.error import ReactorAlreadyInstalledError from zope.interface import implementer from twisted.python import usage from twisted.plugin import IPlugin from twisted.application.service import IServiceMaker # XXX: We need to configure logs before any log method is used, so here is the best place. +from libervia.backend.core import exceptions from libervia.backend.core.constants import Const as C from libervia.backend.core.i18n import _ @@ -33,7 +35,8 @@ install_wokkel_patches() def initialise(options): """Method to initialise global modules""" - # XXX: We need to configure logs before any log method is used, so here is the best place. + # XXX: We need to configure logs before any log method is used, so here is the best + # place. from libervia.backend.core import log_config log_config.libervia_configure(C.LOG_BACKEND_TWISTED, C, backend_data=options) @@ -67,7 +70,15 @@ class LiberviaMaker: def makeService(self, options): from twisted.internet import asyncioreactor - asyncioreactor.install() + try: + asyncioreactor.install() + except ReactorAlreadyInstalledError as e: + from twisted.internet import reactor + + if not isinstance(reactor, asyncioreactor.AsyncioSelectorReactor): + raise exceptions.InternalError( + f"Wrong reactor installed: {reactor}" + ) from e self.set_debugger() # XXX: Libervia must be imported after log configuration, # because it write stuff to logs