From d9eac6659aec6d0199ccf9d8b9078970397e281e Mon Sep 17 00:00:00 2001 From: John Thiltges Date: Fri, 26 May 2023 15:36:43 -0500 Subject: [PATCH 1/2] Periodically reload topology data in a background thread --- src/app.py | 31 +++++++++++++++++++++++++++++++ src/webapp/models.py | 28 +++++++++++++++++----------- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/app.py b/src/app.py index 366ab6a4d..8033a097d 100755 --- a/src/app.py +++ b/src/app.py @@ -8,11 +8,13 @@ from io import StringIO import logging import os +import random import re import sys import traceback import urllib.parse import requests +import threading from wtforms import ValidationError from flask_wtf.csrf import CSRFProtect @@ -116,6 +118,35 @@ def _verify_config(cfg): csrf = CSRFProtect() csrf.init_app(app) +############################################################################# +# Background update thread +# Run when the topology cache is 2/3 to expiration +bg_update_freq = min(global_data.topology.cache_lifetime*2/3, 60) # seconds +bg_update_thread = threading.Thread() + +def bg_update_run(): + '''Background update task''' + app.logger.debug('Background update started') + global_data.update_topology() + + # Add +/- 10% random offset to avoid thundering herds + delay = bg_update_freq + delay *= random.uniform(0.9, 1.1) + + # Set next run + global bg_update_thread + bg_update_thread = threading.Timer(delay, bg_update_run, ()) + bg_update_thread.daemon = True + bg_update_thread.start() + app.logger.info('Background update complete') + +# Start background update thread +bg_update_thread = threading.Timer(bg_update_freq, bg_update_run, ()) +# Make it a daemon thread, so interpreter won't wait on it when exiting +bg_update_thread.daemon = True +bg_update_thread.start() +############################################################################# + def _fix_unicode(text): """Convert a partial unicode string to full unicode""" diff --git a/src/webapp/models.py b/src/webapp/models.py index d8748ee74..21df4c8f9 100644 --- a/src/webapp/models.py +++ b/src/webapp/models.py @@ -261,20 +261,26 @@ def get_topology(self) -> Optional[Topology]: May return None if we fail to get the data for the first time. """ if self.topology.should_update(): - ok = self._update_topology_repo() - if ok: - try: - self.topology.update(rg_reader.get_topology(self.topology_dir, self.get_contacts_data(), strict=self.strict)) - except Exception: - if self.strict: - raise - log.exception("Failed to update topology") - self.topology.try_again() - else: - self.topology.try_again() + self.update_topology() return self.topology.data + def update_topology(self): + """ + Update topology data + """ + ok = self._update_topology_repo() + if ok: + try: + self.topology.update(rg_reader.get_topology(self.topology_dir, self.get_contacts_data(), strict=self.strict)) + except Exception: + if self.strict: + raise + log.exception("Failed to update topology") + self.topology.try_again() + else: + self.topology.try_again() + def get_vos_data(self) -> Optional[VOsData]: """ Get VO Data. From bc07037b74fcef3c71195f15d73dd016c1ae1032 Mon Sep 17 00:00:00 2001 From: John Thiltges Date: Tue, 30 Apr 2024 16:42:56 -0500 Subject: [PATCH 2/2] Fix bg_update_freq logic, using max instead of min. Thanks for noticing it, Mat! --- src/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.py b/src/app.py index 8033a097d..eddc96d49 100755 --- a/src/app.py +++ b/src/app.py @@ -121,7 +121,7 @@ def _verify_config(cfg): ############################################################################# # Background update thread # Run when the topology cache is 2/3 to expiration -bg_update_freq = min(global_data.topology.cache_lifetime*2/3, 60) # seconds +bg_update_freq = max(global_data.topology.cache_lifetime*2/3, 60) # seconds bg_update_thread = threading.Thread() def bg_update_run():