diff --git a/src/app.py b/src/app.py index cf0c92cf5..75e01bb40 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 = max(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 d9288586d..1b51c1a65 100644 --- a/src/webapp/models.py +++ b/src/webapp/models.py @@ -288,20 +288,26 @@ def get_topology(self) -> Optional[Topology]: """ if self.topology.should_update(): with topology_update_summary.time(): - 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.