moonraker: refactor component initialization

Components may call a "component_init" method for initialization that requires async calls.  This allows moonraker to track init progress and guarantee init order.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2021-11-02 12:16:37 -04:00 committed by Eric Callahan
parent 7a8aeae673
commit cbdbe83bbd
1 changed files with 36 additions and 11 deletions

View File

@ -146,6 +146,9 @@ class Server:
self._load_components(config) self._load_components(config)
self.klippy_apis: KlippyAPI = self.lookup_component('klippy_apis') self.klippy_apis: KlippyAPI = self.lookup_component('klippy_apis')
config.validate_config() config.validate_config()
self.event_loop.add_signal_handler(
signal.SIGTERM, self._handle_term_signal)
self.event_loop.register_callback(self._start_server)
def get_app_args(self) -> Dict[str, Any]: def get_app_args(self) -> Dict[str, Any]:
return dict(self.app_args) return dict(self.app_args)
@ -153,16 +156,30 @@ class Server:
def get_event_loop(self) -> EventLoop: def get_event_loop(self) -> EventLoop:
return self.event_loop return self.event_loop
def start(self) -> None: async def _start_server(self):
optional_comps: List[Coroutine] = []
for name, component in self.components.items():
if not hasattr(component, "component_init"):
continue
if name in CORE_COMPONENTS:
# Process core components in order synchronously
await self._initialize_component(name, component)
else:
optional_comps.append(
self._initialize_component(name, component))
# Asynchronous Optional Component Initialization
if optional_comps:
await asyncio.gather(*optional_comps)
# Start HTTP Server
hostname, hostport = self.get_host_info() hostname, hostport = self.get_host_info()
logging.info( logging.info(
f"Starting Moonraker on ({self.host}, {hostport}), " f"Starting Moonraker on ({self.host}, {hostport}), "
f"Hostname: {hostname}") f"Hostname: {hostname}")
self.moonraker_app.listen(self.host, self.port, self.ssl_port) self.moonraker_app.listen(self.host, self.port, self.ssl_port)
self.server_running = True self.server_running = True
self.event_loop.add_signal_handler( await self._connect_klippy()
signal.SIGTERM, self._handle_term_signal)
self.event_loop.register_callback(self._connect_klippy)
def add_log_rollover_item(self, name: str, item: str, def add_log_rollover_item(self, name: str, item: str,
log: bool = True) -> None: log: bool = True) -> None:
@ -177,6 +194,17 @@ class Server:
logging.warning(warning) logging.warning(warning)
# ***** Component Management ***** # ***** Component Management *****
async def _initialize_component(self, name: str, component: Any) -> None:
logging.info(f"Performing Component Post Init: [{name}]")
try:
ret = component.component_init()
if ret is not None:
await ret
except Exception as e:
self.add_warning(f"Component '{name}' failed to load with "
f"error: {e}")
self.set_failed_component(name)
def _load_components(self, config: confighelper.ConfigHelper) -> None: def _load_components(self, config: confighelper.ConfigHelper) -> None:
# load core components # load core components
for component in CORE_COMPONENTS: for component in CORE_COMPONENTS:
@ -275,8 +303,8 @@ class Server:
if not ret: if not ret:
self.event_loop.delay_callback(.25, self._connect_klippy) self.event_loop.delay_callback(.25, self._connect_klippy)
return return
# begin server iniialization self.init_handle = self.event_loop.delay_callback(
self.event_loop.register_callback(self._initialize) 0.01, self._init_klippy_connection)
def process_command(self, cmd: Dict[str, Any]) -> None: def process_command(self, cmd: Dict[str, Any]) -> None:
method = cmd.get('method', None) method = cmd.get('method', None)
@ -332,7 +360,7 @@ class Server:
if self.klippy_disconnect_evt is not None: if self.klippy_disconnect_evt is not None:
self.klippy_disconnect_evt.set() self.klippy_disconnect_evt.set()
async def _initialize(self) -> None: async def _init_klippy_connection(self) -> None:
if not self.server_running: if not self.server_running:
return return
await self._check_ready() await self._check_ready()
@ -368,7 +396,7 @@ class Server:
else: else:
self.init_attempts += 1 self.init_attempts += 1
self.init_handle = self.event_loop.delay_callback( self.init_handle = self.event_loop.delay_callback(
INIT_TIME, self._initialize) INIT_TIME, self._init_klippy_connection)
async def _request_endpoints(self) -> None: async def _request_endpoints(self) -> None:
result = await self.klippy_apis.list_endpoints(default=None) result = await self.klippy_apis.list_endpoints(default=None)
@ -613,8 +641,6 @@ class Server:
'klippy_state': self.klippy_state, 'klippy_state': self.klippy_state,
'components': list(self.components.keys()), 'components': list(self.components.keys()),
'failed_components': self.failed_components, 'failed_components': self.failed_components,
'plugins': list(self.components.keys()),
'failed_plugins': self.failed_components,
'registered_directories': reg_dirs, 'registered_directories': reg_dirs,
'warnings': self.warnings, 'warnings': self.warnings,
'websocket_count': self.get_websocket_manager().get_count(), 'websocket_count': self.get_websocket_manager().get_count(),
@ -779,7 +805,6 @@ def main() -> None:
estatus = 1 estatus = 1
break break
try: try:
server.start()
event_loop.start() event_loop.start()
except Exception: except Exception:
logging.exception("Server Running Error") logging.exception("Server Running Error")