app: During startup, run post-init operation in background

- This allows for the service to become "ready" and serving web connection sooner.

- If some operations such as obtaining certificates and domain configurations
are happening, these can be shown as operations with UI notifications.

Tests:

- Running 'freedombox-develop --setup' works. 'App initialization completed'
message is printed before 'Running setup...' message. Process exits
successfully.

- Running 'freedombox-develop --setup-no-install' works. 'App initialization
completed' message is printed before 'Running setup...' message. Process exits
successfully.

- Running 'freedombox-develop' works. 'App initialization completed' message is
printed before 'Running regular setup' and 'Setup finished'. Cherrypy starts
listening before 'App initialization completed' message.

- Running a fresh VM setup works.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2025-04-04 15:27:57 -07:00 committed by James Valleroy
parent a8eba9e719
commit 6cc71aa5d7
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 17 additions and 20 deletions

View File

@ -4,6 +4,7 @@
import argparse
import logging
import sys
import threading
from . import __version__
from . import app as app_module
@ -95,6 +96,13 @@ def on_web_server_stop():
glib.stop()
def run_post_init_and_setup():
"""Run post-init operations on the apps and setup operations."""
app_module.apps_post_init()
frontpage.add_custom_shortcuts()
setup.run_setup_on_startup() # Long running, retrying
def main():
"""Initialize and start the application"""
arguments = parse_arguments()
@ -134,16 +142,16 @@ def main():
module_loader.load_modules()
app_module.apps_init()
app_module.apps_post_init()
frontpage.add_custom_shortcuts()
if arguments.setup is not False:
app_module.apps_post_init()
run_setup_and_exit(arguments.setup, allow_install=True)
if arguments.setup_no_install is not False:
app_module.apps_post_init()
run_setup_and_exit(arguments.setup_no_install, allow_install=False)
setup.run_setup_in_background()
threading.Thread(target=run_post_init_and_setup).start()
glib.run()

View File

@ -26,7 +26,6 @@ from .privileged import packages as packages_privileged
logger = logging.getLogger(__name__)
_is_first_setup = False
is_first_setup_running = False
_is_shutting_down = False
@ -273,18 +272,15 @@ def list_dependencies(app_ids=None, essential=False):
print(package_expression)
def run_setup_in_background():
"""Run setup in a background thread."""
_set_is_first_setup()
threading.Thread(target=_run_setup_on_startup).start()
def _run_setup_on_startup():
def run_setup_on_startup():
"""Run setup with retry till it succeeds."""
is_first_setup = any((app for app in app_module.App.list()
if app.info.is_essential and app.needs_setup()))
sleep_time = 10
while True:
try:
if _is_first_setup:
if is_first_setup:
logger.info('Running first setup.')
_run_first_setup()
break
@ -299,7 +295,7 @@ def _run_setup_on_startup():
if _is_shutting_down:
break
logger.info('Setup thread finished.')
logger.info('Setup finished.')
def _run_first_setup():
@ -337,13 +333,6 @@ def _get_apps_for_regular_setup():
]
def _set_is_first_setup():
"""Set whether all essential apps have been setup at least once."""
global _is_first_setup
_is_first_setup = any((app for app in app_module.App.list()
if app.info.is_essential and app.needs_setup()))
def run_setup_on_apps(app_ids, allow_install=True):
"""Run setup on the given list of apps.