FreedomBox/plinth/glib.py
Sunil Mohan Adapa 996596ddc0
glib: Add schedule parameter for setting interval in develop mode
Tests:

- In development mode, diagnostics task runs after about 180 seconds (with
jitter).

- In production mode, diagnostics task does not run after 180 seconds.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Veiko Aasa <veiko17@disroot.org>
2025-09-29 16:58:38 +03:00

92 lines
2.5 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Module to handle glib main loop and provide asynchronous utilities.
"""
import logging
import random
import threading
from plinth import dbus, network
from plinth.utils import import_from_gi
from . import cfg
glib = import_from_gi('GLib', '2.0')
_thread = None
_main_loop = None
logger = logging.getLogger(__name__)
def run():
"""Run a glib main loop forever in a thread."""
global _thread
_thread = threading.Thread(target=_run)
_thread.start()
def stop():
"""Exit glib main loop and end the thread."""
if _main_loop:
logger.info('Exiting glib main loop')
_main_loop.quit()
def _run():
"""Connect to D-Bus and run main loop."""
logger.info('Started new thread for glib main loop.')
# Initialize all modules that use glib main loop
dbus.init()
network.init()
global _main_loop
_main_loop = glib.MainLoop()
_main_loop.run()
_main_loop = None
logger.info('Glib main loop thread exited.')
def schedule(interval, method, data=None, in_thread=True, repeat=True,
add_jitter=True, develop_interval=None):
"""Schedule a recurring call to a method with fixed interval.
develop_interval is number of seconds to schedule the task after when
running in development mode. A value of 180 seconds assumed if the value is
set to None or 0.
"""
def _runner():
"""Run the target method and log and exceptions."""
try:
return method(data)
except Exception as exception: # pylint: disable=broad-except
logger.exception('Exception in running scheduled method - %s',
exception)
def _run_bare_or_thread(_user_data):
"""Run the target method in thread or directly (if async)."""
if not in_thread:
_runner()
return repeat
thread = threading.Thread(target=_runner)
thread.start()
return repeat
# When running in development mode, reduce the interval for tasks so that
# they are triggered quickly and frequently to facilitate debugging.
if cfg.develop:
interval = min(interval, develop_interval or 180)
if add_jitter:
# Add or subtract 5% random jitter to given interval to avoid many
# tasks running at exactly the same time (and competing for DB, disk,
# network, etc.).
interval *= 0.95 + (random.random() * 0.1)
glib.timeout_add(int(interval * 1000), _run_bare_or_thread, None)