mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
chore: Update database changes application logic in utils and add more RW tests in scheduler + Fix potential bugs and infinite loops
This commit is contained in:
parent
b5a5bd2dd1
commit
186496fe4a
4 changed files with 119 additions and 30 deletions
|
|
@ -482,7 +482,7 @@ class Database:
|
|||
|
||||
return data
|
||||
|
||||
def check_changes(self) -> Union[Dict[str, bool], bool, str]:
|
||||
def check_changes(self, with_date: bool = False) -> Union[Dict[str, Any], str]:
|
||||
"""Check if either the config, the custom configs, plugins or instances have changed inside the database"""
|
||||
with self.__db_session() as session:
|
||||
try:
|
||||
|
|
@ -490,30 +490,66 @@ class Database:
|
|||
session.query(Metadata)
|
||||
.with_entities(
|
||||
Metadata.custom_configs_changed,
|
||||
Metadata.last_custom_configs_change,
|
||||
Metadata.external_plugins_changed,
|
||||
Metadata.last_external_plugins_change,
|
||||
Metadata.pro_plugins_changed,
|
||||
Metadata.last_pro_plugins_change,
|
||||
Metadata.instances_changed,
|
||||
Metadata.last_instances_change,
|
||||
)
|
||||
.filter_by(id=1)
|
||||
.first()
|
||||
)
|
||||
|
||||
return dict(
|
||||
custom_configs_changed=metadata is not None and metadata.custom_configs_changed,
|
||||
external_plugins_changed=metadata is not None and metadata.external_plugins_changed,
|
||||
pro_plugins_changed=metadata is not None and metadata.pro_plugins_changed,
|
||||
instances_changed=metadata is not None and metadata.instances_changed,
|
||||
plugins_config_changed=[plugin.id for plugin in session.query(Plugins).with_entities(Plugins.id).filter_by(config_changed=True).all()],
|
||||
)
|
||||
except BaseException as e:
|
||||
return str(e)
|
||||
base_data = {
|
||||
"custom_configs_changed": False,
|
||||
"external_plugins_changed": False,
|
||||
"pro_plugins_changed": False,
|
||||
"instances_changed": False,
|
||||
}
|
||||
|
||||
def check_plugin_changes(self) -> Union[List[str], str]:
|
||||
"""Check if the plugins have changed inside the database"""
|
||||
with self.__db_session() as session:
|
||||
try:
|
||||
plugins = session.query(Plugins).with_entities(Plugins.id).filter_by(config_changed=True).all()
|
||||
return [plugin.id for plugin in plugins]
|
||||
if with_date:
|
||||
data = base_data | {
|
||||
"last_custom_configs_change": None,
|
||||
"last_external_plugins_change": None,
|
||||
"last_pro_plugins_change": None,
|
||||
"last_instances_change": None,
|
||||
"plugins_config_changed": {
|
||||
plugin.id: plugin.last_config_change
|
||||
for plugin in session.query(Plugins).with_entities(Plugins.id, Plugins.last_config_change).filter_by(config_changed=True).all()
|
||||
},
|
||||
}
|
||||
|
||||
if not metadata:
|
||||
return data
|
||||
|
||||
return data | {
|
||||
"custom_configs_changed": metadata.custom_configs_changed,
|
||||
"last_custom_configs_change": metadata.last_custom_configs_change,
|
||||
"external_plugins_changed": metadata.external_plugins_changed,
|
||||
"last_external_plugins_change": metadata.last_external_plugins_change,
|
||||
"pro_plugins_changed": metadata.pro_plugins_changed,
|
||||
"last_pro_plugins_change": metadata.last_pro_plugins_change,
|
||||
"instances_changed": metadata.instances_changed,
|
||||
"last_instances_change": metadata.last_instances_change,
|
||||
}
|
||||
|
||||
data = base_data | {
|
||||
"plugins_config_changed": sorted(
|
||||
plugin.id for plugin in session.query(Plugins).with_entities(Plugins.id).filter_by(config_changed=True).all()
|
||||
),
|
||||
}
|
||||
|
||||
if not metadata:
|
||||
return data
|
||||
|
||||
return data | {
|
||||
"custom_configs_changed": metadata.custom_configs_changed,
|
||||
"external_plugins_changed": metadata.external_plugins_changed,
|
||||
"pro_plugins_changed": metadata.pro_plugins_changed,
|
||||
"instances_changed": metadata.instances_changed,
|
||||
}
|
||||
except BaseException as e:
|
||||
return str(e)
|
||||
|
||||
|
|
@ -536,23 +572,31 @@ class Database:
|
|||
if not metadata:
|
||||
return "The metadata are not set yet, try again"
|
||||
|
||||
current_time = datetime.now()
|
||||
|
||||
if "config" in changes:
|
||||
if not metadata.first_config_saved:
|
||||
metadata.first_config_saved = True
|
||||
if "custom_configs" in changes:
|
||||
metadata.custom_configs_changed = value
|
||||
metadata.last_custom_configs_change = current_time
|
||||
if "external_plugins" in changes:
|
||||
metadata.external_plugins_changed = value
|
||||
metadata.last_external_plugins_change = current_time
|
||||
if "pro_plugins" in changes:
|
||||
metadata.pro_plugins_changed = value
|
||||
metadata.last_pro_plugins_change = current_time
|
||||
if "instances" in changes:
|
||||
metadata.instances_changed = value
|
||||
metadata.last_instances_change = current_time
|
||||
|
||||
if plugins_changes:
|
||||
if plugins_changes == "all":
|
||||
session.query(Plugins).update({Plugins.config_changed: value})
|
||||
session.query(Plugins).update({Plugins.config_changed: value, Plugins.last_config_change: current_time})
|
||||
else:
|
||||
session.query(Plugins).filter(Plugins.id.in_(plugins_changes)).update({Plugins.config_changed: value})
|
||||
session.query(Plugins).filter(Plugins.id.in_(plugins_changes)).update(
|
||||
{Plugins.config_changed: value, Plugins.last_config_change: current_time}
|
||||
)
|
||||
|
||||
session.commit()
|
||||
except BaseException as e:
|
||||
|
|
@ -581,7 +625,7 @@ class Database:
|
|||
|
||||
if db_version != bunkerweb_version:
|
||||
self.logger.warning(f"Database version ({db_version}) is different from Bunkerweb version ({bunkerweb_version}), migrating ...")
|
||||
curren_time = datetime.now()
|
||||
current_time = datetime.now()
|
||||
error = True
|
||||
while error:
|
||||
try:
|
||||
|
|
@ -589,7 +633,7 @@ class Database:
|
|||
metadata.reflect(self.sql_engine)
|
||||
error = False
|
||||
except BaseException as e:
|
||||
if (datetime.now() - curren_time).total_seconds() > 10:
|
||||
if (datetime.now() - current_time).total_seconds() > 10:
|
||||
raise e
|
||||
sleep(1)
|
||||
|
||||
|
|
@ -1455,6 +1499,7 @@ class Database:
|
|||
metadata = session.query(Metadata).get(1)
|
||||
if metadata is not None:
|
||||
metadata.custom_configs_changed = True
|
||||
metadata.last_custom_configs_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
@ -2181,8 +2226,10 @@ class Database:
|
|||
if metadata is not None:
|
||||
if _type == "external":
|
||||
metadata.external_plugins_changed = True
|
||||
metadata.last_external_plugins_change = datetime.now()
|
||||
elif _type == "pro":
|
||||
metadata.pro_plugins_changed = True
|
||||
metadata.last_pro_plugins_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
@ -2398,6 +2445,7 @@ class Database:
|
|||
metadata = session.query(Metadata).get(1)
|
||||
if metadata is not None:
|
||||
metadata.instances_changed = True
|
||||
metadata.last_instances_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.commit()
|
||||
|
|
@ -2429,6 +2477,7 @@ class Database:
|
|||
metadata = session.query(Metadata).get(1)
|
||||
if metadata is not None:
|
||||
metadata.instances_changed = True
|
||||
metadata.last_instances_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class Plugins(Base):
|
|||
data = Column(LargeBinary(length=(2**32) - 1), nullable=True)
|
||||
checksum = Column(String(128), nullable=True)
|
||||
config_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_config_change = Column(DateTime, nullable=True)
|
||||
|
||||
settings = relationship("Settings", back_populates="plugin", cascade="all, delete-orphan")
|
||||
jobs = relationship("Jobs", back_populates="plugin", cascade="all, delete-orphan")
|
||||
|
|
@ -242,8 +243,12 @@ class Metadata(Base):
|
|||
autoconf_loaded = Column(Boolean, default=False, nullable=True)
|
||||
scheduler_first_start = Column(Boolean, nullable=True)
|
||||
custom_configs_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_custom_configs_change = Column(DateTime, nullable=True)
|
||||
external_plugins_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_external_plugins_change = Column(DateTime, nullable=True)
|
||||
pro_plugins_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_pro_plugins_change = Column(DateTime, nullable=True)
|
||||
instances_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_instances_change = Column(DateTime, nullable=True)
|
||||
integration = Column(INTEGRATIONS_ENUM, default="Unknown", nullable=False)
|
||||
version = Column(String(32), default="1.5.8", nullable=False)
|
||||
|
|
|
|||
|
|
@ -360,14 +360,16 @@ class JobScheduler(ApiCaller):
|
|||
return False
|
||||
return ret
|
||||
|
||||
def try_database_readonly(self) -> bool:
|
||||
def try_database_readonly(self, force: bool = False) -> bool:
|
||||
if not self.db.readonly:
|
||||
try:
|
||||
self.db.test_write()
|
||||
self.db.readonly = False
|
||||
return False
|
||||
except BaseException:
|
||||
self.db.readonly = True
|
||||
return True
|
||||
elif self.db.last_connection_retry and (datetime.now() - self.db.last_connection_retry).total_seconds() > 30:
|
||||
elif not force and self.db.last_connection_retry and (datetime.now() - self.db.last_connection_retry).total_seconds() > 30:
|
||||
return True
|
||||
|
||||
if self.db.database_uri and self.db.readonly:
|
||||
|
|
|
|||
|
|
@ -663,6 +663,7 @@ if __name__ == "__main__":
|
|||
Thread(target=listen_for_instances_reload, name="listen_for_instances_reload").start()
|
||||
|
||||
changed_plugins = []
|
||||
old_changes = {}
|
||||
|
||||
while True:
|
||||
threads.clear()
|
||||
|
|
@ -788,7 +789,7 @@ if __name__ == "__main__":
|
|||
while RUN and not NEED_RELOAD:
|
||||
try:
|
||||
SCHEDULER.run_pending()
|
||||
sleep(1)
|
||||
sleep(3 if SCHEDULER.db.readonly else 1)
|
||||
current_time = datetime.now()
|
||||
|
||||
while DB_LOCK_FILE.is_file() and DB_LOCK_FILE.stat().st_ctime + 30 > current_time.timestamp():
|
||||
|
|
@ -797,20 +798,33 @@ if __name__ == "__main__":
|
|||
|
||||
DB_LOCK_FILE.unlink(missing_ok=True)
|
||||
|
||||
changes = SCHEDULER.db.check_changes()
|
||||
changes = SCHEDULER.db.check_changes(with_date=True)
|
||||
|
||||
if isinstance(changes, str):
|
||||
raise Exception(f"An error occurred when checking for changes in the database : {changes}")
|
||||
|
||||
if SCHEDULER.db.readonly and changes == old_changes:
|
||||
continue
|
||||
|
||||
# check if the plugins have changed since last time
|
||||
if changes["pro_plugins_changed"]:
|
||||
if changes["pro_plugins_changed"] and (
|
||||
not SCHEDULER.db.readonly
|
||||
or not changes["last_pro_plugins_change"]
|
||||
or not old_changes
|
||||
or old_changes["last_pro_plugins_change"] != changes["last_pro_plugins_change"]
|
||||
):
|
||||
logger.info("Pro plugins changed, generating ...")
|
||||
PRO_PLUGINS_NEED_GENERATION = True
|
||||
CONFIG_NEED_GENERATION = True
|
||||
RUN_JOBS_ONCE = True
|
||||
NEED_RELOAD = True
|
||||
|
||||
if changes["external_plugins_changed"]:
|
||||
if changes["external_plugins_changed"] and (
|
||||
not SCHEDULER.db.readonly
|
||||
or not changes["last_external_plugins_change"]
|
||||
or not old_changes
|
||||
or old_changes["last_external_plugins_change"] != changes["last_external_plugins_change"]
|
||||
):
|
||||
logger.info("External plugins changed, generating ...")
|
||||
PLUGINS_NEED_GENERATION = True
|
||||
CONFIG_NEED_GENERATION = True
|
||||
|
|
@ -818,27 +832,44 @@ if __name__ == "__main__":
|
|||
NEED_RELOAD = True
|
||||
|
||||
# check if the custom configs have changed since last time
|
||||
if changes["custom_configs_changed"]:
|
||||
if changes["custom_configs_changed"] and (
|
||||
not SCHEDULER.db.readonly
|
||||
or not changes["last_custom_configs_change"]
|
||||
or not old_changes
|
||||
or old_changes["last_custom_configs_change"] != changes["last_custom_configs_change"]
|
||||
):
|
||||
logger.info("Custom configs changed, generating ...")
|
||||
CONFIGS_NEED_GENERATION = True
|
||||
CONFIG_NEED_GENERATION = True
|
||||
NEED_RELOAD = True
|
||||
|
||||
# check if the config have changed since last time
|
||||
if changes["plugins_config_changed"]:
|
||||
if changes["plugins_config_changed"] and (
|
||||
not SCHEDULER.db.readonly
|
||||
or not changes["last_plugins_config_change"]
|
||||
or not old_changes
|
||||
or old_changes["plugins_config_changed"] != changes["plugins_config_changed"]
|
||||
):
|
||||
logger.info("Plugins config changed, generating ...")
|
||||
CONFIG_NEED_GENERATION = True
|
||||
RUN_JOBS_ONCE = True
|
||||
NEED_RELOAD = True
|
||||
changed_plugins = changes["plugins_config_changed"]
|
||||
changed_plugins = list(changes["plugins_config_changed"])
|
||||
|
||||
# check if the instances have changed since last time
|
||||
if changes["instances_changed"]:
|
||||
if changes["instances_changed"] and (
|
||||
not SCHEDULER.db.readonly
|
||||
or not changes["last_instances_change"]
|
||||
or not old_changes
|
||||
or old_changes["last_instances_change"] != changes["last_instances_change"]
|
||||
):
|
||||
logger.info("Instances changed, generating ...")
|
||||
INSTANCES_NEED_GENERATION = True
|
||||
CONFIGS_NEED_GENERATION = True
|
||||
CONFIG_NEED_GENERATION = True
|
||||
NEED_RELOAD = True
|
||||
|
||||
old_changes = changes.copy()
|
||||
except BaseException:
|
||||
logger.debug(format_exc())
|
||||
if errors > 5:
|
||||
|
|
@ -848,6 +879,8 @@ if __name__ == "__main__":
|
|||
sleep(5)
|
||||
|
||||
if NEED_RELOAD:
|
||||
logger.debug(f"Changes: {changes}")
|
||||
SCHEDULER.try_database_readonly(force=True)
|
||||
CHANGES.clear()
|
||||
|
||||
if INSTANCES_NEED_GENERATION:
|
||||
|
|
|
|||
Loading…
Reference in a new issue