server: refactor startup
Use asyncio.run() to launch the server application as recommended by the Python docs. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
3a42dac02b
commit
0a8590643f
|
@ -1108,7 +1108,10 @@ class FileSourceWrapper(ConfigSourceWrapper):
|
||||||
def get_configuration(
|
def get_configuration(
|
||||||
server: Server, app_args: Dict[str, Any]
|
server: Server, app_args: Dict[str, Any]
|
||||||
) -> ConfigHelper:
|
) -> ConfigHelper:
|
||||||
start_path = pathlib.Path(app_args['config_file']).expanduser().resolve()
|
cfg_file = app_args["config_file"]
|
||||||
|
if app_args["is_backup_config"]:
|
||||||
|
cfg_file = app_args["backup_config"]
|
||||||
|
start_path = pathlib.Path(cfg_file).expanduser().absolute()
|
||||||
source = FileSourceWrapper(server)
|
source = FileSourceWrapper(server)
|
||||||
source.read_file(start_path)
|
source.read_file(start_path)
|
||||||
if not source.config.has_section('server'):
|
if not source.config.has_section('server'):
|
||||||
|
|
|
@ -27,7 +27,7 @@ _uvl_var = os.getenv("MOONRAKER_ENABLE_UVLOOP", "y").lower()
|
||||||
_uvl_enabled = False
|
_uvl_enabled = False
|
||||||
if _uvl_var in ["y", "yes", "true"]:
|
if _uvl_var in ["y", "yes", "true"]:
|
||||||
with contextlib.suppress(ImportError):
|
with contextlib.suppress(ImportError):
|
||||||
import uvloop
|
import uvloop # type: ignore
|
||||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||||
_uvl_enabled = True
|
_uvl_enabled = True
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class EventLoop:
|
||||||
return self.aioloop
|
return self.aioloop
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
self.aioloop = self._create_new_loop()
|
self.aioloop = asyncio.get_running_loop()
|
||||||
self.add_signal_handler = self.aioloop.add_signal_handler
|
self.add_signal_handler = self.aioloop.add_signal_handler
|
||||||
self.remove_signal_handler = self.aioloop.remove_signal_handler
|
self.remove_signal_handler = self.aioloop.remove_signal_handler
|
||||||
self.add_reader = self.aioloop.add_reader
|
self.add_reader = self.aioloop.add_reader
|
||||||
|
@ -126,7 +126,7 @@ class EventLoop:
|
||||||
host, port, family=0, type=socket.SOCK_STREAM
|
host, port, family=0, type=socket.SOCK_STREAM
|
||||||
)
|
)
|
||||||
for res in ainfo:
|
for res in ainfo:
|
||||||
af, socktype, proto, canonname, sa = res
|
af, socktype, proto, _cannon_name, _sa = res
|
||||||
sock = None
|
sock = None
|
||||||
try:
|
try:
|
||||||
sock = socket.socket(af, socktype, proto)
|
sock = socket.socket(af, socktype, proto)
|
||||||
|
@ -152,12 +152,6 @@ class EventLoop:
|
||||||
else:
|
else:
|
||||||
raise socket.error("getaddrinfo returns an empty list")
|
raise socket.error("getaddrinfo returns an empty list")
|
||||||
|
|
||||||
def start(self):
|
|
||||||
self.aioloop.run_forever()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.aioloop.stop()
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.aioloop.close()
|
self.aioloop.close()
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ class LogManager:
|
||||||
return eventloop.run_in_thread(self.file_hdlr.doRollover)
|
return eventloop.run_in_thread(self.file_hdlr.doRollover)
|
||||||
|
|
||||||
def stop_logging(self):
|
def stop_logging(self):
|
||||||
|
if self.listener is not None:
|
||||||
self.listener.stop()
|
self.listener.stop()
|
||||||
|
|
||||||
async def _handle_log_rollover(
|
async def _handle_log_rollover(
|
||||||
|
|
|
@ -89,6 +89,7 @@ class Server:
|
||||||
self.ssl_port: int = config.getint('ssl_port', 7130)
|
self.ssl_port: int = config.getint('ssl_port', 7130)
|
||||||
self.exit_reason: str = ""
|
self.exit_reason: str = ""
|
||||||
self.server_running: bool = False
|
self.server_running: bool = False
|
||||||
|
self.app_running_evt = asyncio.Event()
|
||||||
self.pip_recovery_attempted: bool = False
|
self.pip_recovery_attempted: bool = False
|
||||||
|
|
||||||
# Configure Debug Logging
|
# Configure Debug Logging
|
||||||
|
@ -198,10 +199,8 @@ class Server:
|
||||||
await self.event_loop.run_in_thread(self.config.create_backup)
|
await self.event_loop.run_in_thread(self.config.create_backup)
|
||||||
|
|
||||||
machine: Machine = self.lookup_component("machine")
|
machine: Machine = self.lookup_component("machine")
|
||||||
if await machine.validate_installation():
|
restarting = await machine.validate_installation()
|
||||||
return
|
if not restarting and start_server:
|
||||||
|
|
||||||
if start_server:
|
|
||||||
await self.start_server()
|
await self.start_server()
|
||||||
|
|
||||||
async def start_server(self, connect_to_klippy: bool = True) -> None:
|
async def start_server(self, connect_to_klippy: bool = True) -> None:
|
||||||
|
@ -218,6 +217,9 @@ class Server:
|
||||||
if connect_to_klippy:
|
if connect_to_klippy:
|
||||||
self.klippy_connection.connect()
|
self.klippy_connection.connect()
|
||||||
|
|
||||||
|
async def run_until_exit(self) -> None:
|
||||||
|
await self.app_running_evt.wait()
|
||||||
|
|
||||||
def add_log_rollover_item(
|
def add_log_rollover_item(
|
||||||
self, name: str, item: str, log: bool = True
|
self, name: str, item: str, log: bool = True
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -488,7 +490,7 @@ class Server:
|
||||||
|
|
||||||
self.exit_reason = exit_reason
|
self.exit_reason = exit_reason
|
||||||
self.event_loop.remove_signal_handler(signal.SIGTERM)
|
self.event_loop.remove_signal_handler(signal.SIGTERM)
|
||||||
self.event_loop.stop()
|
self.app_running_evt.set()
|
||||||
|
|
||||||
async def _handle_server_restart(self, web_request: WebRequest) -> str:
|
async def _handle_server_restart(self, web_request: WebRequest) -> str:
|
||||||
self.event_loop.register_callback(self._stop_server)
|
self.event_loop.register_callback(self._stop_server)
|
||||||
|
@ -540,6 +542,45 @@ class Server:
|
||||||
'files': cfg_file_list
|
'files': cfg_file_list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async def launch_server(
|
||||||
|
log_manager: LogManager, app_args: Dict[str, Any]
|
||||||
|
) -> Optional[int]:
|
||||||
|
eventloop = EventLoop()
|
||||||
|
startup_warnings: List[str] = app_args["startup_warnings"]
|
||||||
|
try:
|
||||||
|
server = Server(app_args, log_manager, eventloop)
|
||||||
|
server.load_components()
|
||||||
|
except confighelper.ConfigError as e:
|
||||||
|
logging.exception("Server Config Error")
|
||||||
|
backup_cfg: Optional[str] = app_args["backup_config"]
|
||||||
|
if app_args["is_backup_config"] or backup_cfg is None:
|
||||||
|
return 1
|
||||||
|
app_args["is_backup_config"] = True
|
||||||
|
startup_warnings.append(
|
||||||
|
f"Server configuration error: {e}\n"
|
||||||
|
f"Loading most recent working configuration: '{backup_cfg}'\n"
|
||||||
|
f"Please fix the issue in moonraker.conf and restart the server."
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Moonraker Error")
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
await server.server_init()
|
||||||
|
await server.run_until_exit()
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Server Running Error")
|
||||||
|
return 1
|
||||||
|
if server.exit_reason == "terminate":
|
||||||
|
return 0
|
||||||
|
# Restore the original config and clear the warning
|
||||||
|
# before the server restarts
|
||||||
|
if app_args["is_backup_config"]:
|
||||||
|
startup_warnings.pop()
|
||||||
|
app_args["is_backup_config"] = False
|
||||||
|
del server
|
||||||
|
return None
|
||||||
|
|
||||||
def main(from_package: bool = True) -> None:
|
def main(from_package: bool = True) -> None:
|
||||||
def get_env_bool(key: str) -> bool:
|
def get_env_bool(key: str) -> bool:
|
||||||
return os.getenv(key, "").lower() in ["y", "yes", "true"]
|
return os.getenv(key, "").lower() in ["y", "yes", "true"]
|
||||||
|
@ -635,6 +676,7 @@ def main(from_package: bool = True) -> None:
|
||||||
"data_path": str(data_path),
|
"data_path": str(data_path),
|
||||||
"is_default_data_path": cmd_line_args.datapath is None,
|
"is_default_data_path": cmd_line_args.datapath is None,
|
||||||
"config_file": cfg_file,
|
"config_file": cfg_file,
|
||||||
|
"backup_config": confighelper.find_config_backup(cfg_file),
|
||||||
"startup_warnings": startup_warnings,
|
"startup_warnings": startup_warnings,
|
||||||
"verbose": cmd_line_args.verbose,
|
"verbose": cmd_line_args.verbose,
|
||||||
"debug": cmd_line_args.debug,
|
"debug": cmd_line_args.debug,
|
||||||
|
@ -661,60 +703,14 @@ def main(from_package: bool = True) -> None:
|
||||||
log_manager = LogManager(app_args, startup_warnings)
|
log_manager = LogManager(app_args, startup_warnings)
|
||||||
|
|
||||||
# Start asyncio event loop and server
|
# Start asyncio event loop and server
|
||||||
event_loop = EventLoop()
|
|
||||||
alt_config_loaded = False
|
|
||||||
estatus = 0
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
estatus = asyncio.run(launch_server(log_manager, app_args))
|
||||||
server = Server(app_args, log_manager, event_loop)
|
if estatus is not None:
|
||||||
server.load_components()
|
|
||||||
except confighelper.ConfigError as e:
|
|
||||||
backup_cfg = confighelper.find_config_backup(cfg_file)
|
|
||||||
logging.exception("Server Config Error")
|
|
||||||
if alt_config_loaded or backup_cfg is None:
|
|
||||||
estatus = 1
|
|
||||||
break
|
break
|
||||||
app_args["config_file"] = backup_cfg
|
|
||||||
app_args["is_backup_config"] = True
|
|
||||||
warn_list = list(startup_warnings)
|
|
||||||
app_args["startup_warnings"] = warn_list
|
|
||||||
warn_list.append(
|
|
||||||
f"Server configuration error: {e}\n"
|
|
||||||
f"Loaded server from most recent working configuration:"
|
|
||||||
f" '{app_args['config_file']}'\n"
|
|
||||||
f"Please fix the issue in moonraker.conf and restart "
|
|
||||||
f"the server."
|
|
||||||
)
|
|
||||||
alt_config_loaded = True
|
|
||||||
continue
|
|
||||||
except Exception:
|
|
||||||
logging.exception("Moonraker Error")
|
|
||||||
estatus = 1
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
event_loop.register_callback(server.server_init)
|
|
||||||
event_loop.start()
|
|
||||||
except Exception:
|
|
||||||
logging.exception("Server Running Error")
|
|
||||||
estatus = 1
|
|
||||||
break
|
|
||||||
if server.exit_reason == "terminate":
|
|
||||||
break
|
|
||||||
# Restore the original config and clear the warning
|
|
||||||
# before the server restarts
|
|
||||||
if alt_config_loaded:
|
|
||||||
app_args["config_file"] = cfg_file
|
|
||||||
app_args["startup_warnings"] = startup_warnings
|
|
||||||
app_args["is_backup_config"] = False
|
|
||||||
alt_config_loaded = False
|
|
||||||
event_loop.close()
|
|
||||||
# Since we are running outside of the the server
|
# Since we are running outside of the the server
|
||||||
# it is ok to use a blocking sleep here
|
# it is ok to use a blocking sleep here
|
||||||
time.sleep(.5)
|
time.sleep(.5)
|
||||||
logging.info("Attempting Server Restart...")
|
logging.info("Attempting Server Restart...")
|
||||||
del server
|
|
||||||
event_loop.reset()
|
|
||||||
event_loop.close()
|
|
||||||
logging.info("Server Shutdown")
|
logging.info("Server Shutdown")
|
||||||
log_manager.stop_logging()
|
log_manager.stop_logging()
|
||||||
exit(estatus)
|
exit(estatus)
|
||||||
|
|
Loading…
Reference in New Issue