Optimize fallback logics on web UI and Scheduler

This commit is contained in:
Théophile Diot 2024-05-28 09:23:55 +01:00
parent 9dd6bbd9ef
commit 673df4d605
No known key found for this signature in database
GPG key ID: 248FEA4BAE400D06
3 changed files with 15 additions and 3 deletions

View file

@ -129,6 +129,7 @@ class Database:
"pool_recycle": 1800,
"pool_size": 40,
"max_overflow": 20,
"pool_timeout": 5,
} | kwargs
try:
@ -215,16 +216,19 @@ class Database:
def test_write(self):
"""Test the write access to the database"""
self.logger.debug("Testing write access to the database ...")
self.retry_connection(pool_timeout=1)
with self.__db_session() as session:
table_name = uuid4().hex
session.execute(text(f"CREATE TABLE IF NOT EXISTS test_{table_name} (id INT)"))
session.execute(text(f"DROP TABLE IF EXISTS test_{table_name}"))
session.commit()
self.retry_connection()
def retry_connection(self, *, readonly: bool = False, fallback: bool = False, **kwargs) -> None:
def retry_connection(self, *, readonly: bool = False, fallback: bool = False, log: bool = True, **kwargs) -> None:
"""Retry the connection to the database"""
self.logger.debug(f"Retrying the connection to the database {'in read-only mode' if readonly else ''}{' with fallback' if fallback else ''} ...")
if log:
self.logger.debug(f"Retrying the connection to the database{' in read-only mode' if readonly else ''}{' with fallback' if fallback else ''} ...")
assert self.sql_engine is not None
@ -265,16 +269,19 @@ class Database:
self.logger.warning("The database is read-only, retrying in read-only mode ...")
try:
self.retry_connection(readonly=True, pool_timeout=1)
self.retry_connection(readonly=True, log=False)
except (OperationalError, DatabaseError):
if self.database_uri_readonly:
self.logger.warning("Can't connect to the database in read-only mode, falling back to read-only one")
with suppress(OperationalError, DatabaseError):
self.retry_connection(fallback=True, pool_timeout=1)
self.retry_connection(fallback=True, log=False)
self.readonly = True
elif isinstance(e, (ConnectionRefusedError, OperationalError)) and self.database_uri_readonly:
self.logger.warning("Can't connect to the database, falling back to read-only one ...")
with suppress(OperationalError, DatabaseError):
self.retry_connection(fallback=True, pool_timeout=1)
self.retry_connection(fallback=True, log=False)
self.readonly = True
raise
finally:

View file

@ -367,19 +367,21 @@ class JobScheduler(ApiCaller):
if self.db.database_uri and self.db.readonly:
try:
self.db.retry_connection(pool_timeout=1)
self.db.retry_connection(log=False)
self.db.readonly = False
self.__logger.info("The database is no longer read-only, defaulting to read-write mode")
except BaseException:
try:
self.db.retry_connection(readonly=True, pool_timeout=1)
self.db.retry_connection(readonly=True, log=False)
except BaseException:
if self.db.database_uri_readonly:
with suppress(BaseException):
self.db.retry_connection(fallback=True, pool_timeout=1)
self.db.retry_connection(fallback=True, log=False)
self.db.readonly = True
if self.db.readonly:
self.__logger.error("Database is in read-only mode, jobs will not be executed")
return True
return self.db.readonly

View file

@ -445,15 +445,18 @@ def before_request():
if app.config["DB"].database_uri and app.config["DB"].readonly:
try:
app.config["DB"].retry_connection(pool_timeout=1)
app.config["DB"].retry_connection(log=False)
app.config["DB"].readonly = False
app.logger.info("The database is no longer read-only, defaulting to read-write mode")
except BaseException:
try:
app.config["DB"].retry_connection(readonly=True, pool_timeout=1)
app.config["DB"].retry_connection(readonly=True, log=False)
except BaseException:
if app.config["DB"].database_uri_readonly:
with suppress(BaseException):
app.config["DB"].retry_connection(fallback=True, pool_timeout=1)
app.config["DB"].retry_connection(fallback=True, log=False)
app.config["DB"].readonly = True
elif not app.config["DB"].readonly and request.method == "POST" and not ("/totp" in request.path or "/login" in request.path):
try: