mirror of
https://github.com/netinvent/npbackup.git
synced 2025-09-06 21:14:38 +08:00
Implement optional random delay for backups
This commit is contained in:
parent
7179342ef5
commit
ceed283969
11 changed files with 61 additions and 4 deletions
|
@ -52,6 +52,7 @@ groups:
|
|||
repo_password:
|
||||
repo_password_command:
|
||||
minimum_backup_age: 1435
|
||||
random_delay_before_backup: 200
|
||||
upload_speed: 800 Mib
|
||||
download_speed: 0 Mib
|
||||
backend_connections: 0
|
||||
|
|
|
@ -52,6 +52,7 @@ groups:
|
|||
repo_password:
|
||||
repo_password_command:
|
||||
minimum_backup_age: 1435
|
||||
random_delay_before_backup: 200
|
||||
upload_speed: 800 Mib
|
||||
download_speed: 0 Mib
|
||||
backend_connections: 0
|
||||
|
|
|
@ -51,6 +51,7 @@ groups:
|
|||
repo_password:
|
||||
repo_password_command:
|
||||
minimum_backup_age: 1435
|
||||
random_delay_before_backup: 200
|
||||
upload_speed: 800 Mib
|
||||
download_speed: 0 Mib
|
||||
backend_connections: 0
|
||||
|
|
|
@ -178,6 +178,7 @@ empty_config_dict = {
|
|||
# Minimum time between two backups, in minutes
|
||||
# Set to zero in order to disable time checks
|
||||
"minimum_backup_age": 1435,
|
||||
"random_delay_before_backup": 200, # Random delay in minutes added to a backup launch
|
||||
"upload_speed": "800 Mib", # allows BytesConverter units, use 0 for unlimited upload speed
|
||||
"download_speed": "0 Mib", # allows BytesConverter units, use 0 for unlimited download speed
|
||||
"backend_connections": 0, # Fine tune simultaneous connections to backend, use 0 for standard configuration
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
# This file is part of npbackup
|
||||
|
||||
__intname__ = "npbackup.gui.core.runner"
|
||||
__intname__ = "npbackup.core.runner"
|
||||
__author__ = "Orsiris de Jong"
|
||||
__copyright__ = "Copyright (C) 2022-2025 NetInvent"
|
||||
__license__ = "GPL-3.0-only"
|
||||
|
@ -15,6 +15,7 @@ import os
|
|||
import logging
|
||||
import tempfile
|
||||
import queue
|
||||
import time
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from functools import wraps
|
||||
from copy import deepcopy
|
||||
|
@ -286,6 +287,7 @@ class NPBackupRunner:
|
|||
self._no_lock = False
|
||||
self.restic_runner = None
|
||||
self.minimum_backup_age = None
|
||||
self.random_delay_before_backup = None
|
||||
self._exec_time = None
|
||||
|
||||
# Error /warning messages to add for json output
|
||||
|
@ -718,6 +720,8 @@ class NPBackupRunner:
|
|||
else:
|
||||
# pylint: disable=E1101 (no-member)
|
||||
operation = fn.__name__
|
||||
|
||||
# Actual operation concurrency check
|
||||
if __check_concurrency and operation in locking_operations:
|
||||
pid_file = os.path.join(
|
||||
tempfile.gettempdir(), "{}.pid".format(__intname__)
|
||||
|
@ -1040,6 +1044,13 @@ class NPBackupRunner:
|
|||
except (KeyError, ValueError, TypeError):
|
||||
# In doubt, launch the backup regardless of last backup age
|
||||
self.minimum_backup_age = 0
|
||||
try:
|
||||
self.random_delay_before_backup = int(
|
||||
self.repo_config.g("repo_opts.random_delay_before_backup")
|
||||
)
|
||||
except (KeyError, ValueError, TypeError):
|
||||
# In doubt, launch the backup regardless of last backup age
|
||||
self.random_delay_before_backup = 0
|
||||
|
||||
self.restic_runner.verbose = self.verbose
|
||||
self.restic_runner.dry_run = self.dry_run
|
||||
|
@ -1308,15 +1319,14 @@ class NPBackupRunner:
|
|||
def backup(
|
||||
self,
|
||||
force: bool = False,
|
||||
honor_delay: bool = True,
|
||||
read_from_stdin: bool = False,
|
||||
stdin_filename: str = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Run backup after checking if no recent backup exists, unless force == True
|
||||
"""
|
||||
|
||||
start_time = datetime.now(timezone.utc)
|
||||
|
||||
repo_name = self.repo_config.g("name")
|
||||
stdin_from_command = self.repo_config.g("backup_opts.stdin_from_command")
|
||||
if not stdin_filename:
|
||||
stdin_filename = self.repo_config.g("backup_opts.stdin_filename")
|
||||
|
@ -1445,6 +1455,30 @@ class NPBackupRunner:
|
|||
return self.convert_to_json_output(True, msg)
|
||||
self.restic_runner.verbose = self.verbose
|
||||
|
||||
# Now add a random delay before backup if configured
|
||||
# We also need to make sure that npbackup executions that happen between this delay don't actually run
|
||||
if self.random_delay_before_backup and honor_delay:
|
||||
# Random delay before backup
|
||||
delay_backup_seconds = randint(0, self.random_delay_before_backup * 60)
|
||||
delay_file = os.path.join(
|
||||
tempfile.gettempdir(), "{}.delay".format(__intname__)
|
||||
)
|
||||
try:
|
||||
with npbackup.pidfile_ng.PIDFile(
|
||||
delay_file, check_full_commandline=False, identifier=repo_name
|
||||
):
|
||||
self.write_logs(
|
||||
f"Delaying backup for {delay_backup_seconds} seconds",
|
||||
level="info",
|
||||
)
|
||||
time.sleep(delay_backup_seconds)
|
||||
except npbackup.pidfile_ng.AlreadyRunningError:
|
||||
self.write_logs(
|
||||
f"There is already a delayed NPBackup operation (full_concurrency = {self.full_concurrency}, repo_aware_concurrency = {self.repo_aware_concurrency}). Will not launch backup to avoid concurrency",
|
||||
level="info",
|
||||
)
|
||||
return True
|
||||
|
||||
# Run backup preps here
|
||||
if source_type in (
|
||||
None,
|
||||
|
|
|
@ -528,6 +528,7 @@ def backup(repo_config: dict) -> bool:
|
|||
__no_lock=__no_lock,
|
||||
__full_concurrency=__full_concurrency,
|
||||
__repo_aware_concurrency=__repo_aware_concurrency,
|
||||
honor_delay=False,
|
||||
)
|
||||
try:
|
||||
return result["result"]
|
||||
|
|
|
@ -1608,6 +1608,20 @@ def config_gui(full_config: dict, config_file: str):
|
|||
sg.Input(key="repo_opts.minimum_backup_age", size=(8, 1)),
|
||||
sg.Text(_t("generic.minutes")),
|
||||
],
|
||||
[
|
||||
sg.Text(
|
||||
_t("config_gui.random_delay_before_backup"),
|
||||
size=(40, 2),
|
||||
),
|
||||
sg.Image(
|
||||
NON_INHERITED_ICON,
|
||||
key="inherited.repo_opts.random_delay_before_backup",
|
||||
tooltip=_t("config_gui.group_inherited"),
|
||||
pad=1,
|
||||
),
|
||||
sg.Input(key="repo_opts.random_delay_before_backup", size=(8, 1)),
|
||||
sg.Text(_t("generic.minutes")),
|
||||
],
|
||||
[
|
||||
sg.Text(_t("config_gui.upload_speed"), size=(40, 1)),
|
||||
sg.Image(
|
||||
|
|
|
@ -32,6 +32,7 @@ en:
|
|||
additional_restore_only_parameters: Additional restore only parameters
|
||||
|
||||
minimum_backup_age: Minimum delay between two backups
|
||||
random_delay_before_backup: Random delay before launching backup
|
||||
backup_repo_uri: backup repo URI / path
|
||||
backup_repo_password: Backup repo encryption password
|
||||
backup_repo_password_command: Command that returns backup repo encryption password
|
||||
|
|
|
@ -33,6 +33,7 @@ fr:
|
|||
additional_restore_only_parameters: Paramètres supplémentaires de restauration
|
||||
|
||||
minimum_backup_age: Délai minimal entre deux sauvegardes
|
||||
random_delay_before_backup: Délai aléatoire avant la sauvegarde
|
||||
backup_repo_uri: URI / chemin local dépot de sauvegarde
|
||||
backup_repo_password: Mot de passe (chiffrement) dépot de sauvegarde
|
||||
backup_repo_password_command: Commande qui retourne le mot de passe de chiffrement dépot
|
||||
|
|
|
@ -54,6 +54,7 @@ groups:
|
|||
repo_password:
|
||||
repo_password_command:
|
||||
minimum_backup_age: 1435
|
||||
random_delay_before_backup: 200
|
||||
upload_speed: 100 Mib
|
||||
download_speed: 0 Mib
|
||||
backend_connections: 0
|
||||
|
|
|
@ -55,6 +55,7 @@ groups:
|
|||
repo_password:
|
||||
repo_password_command:
|
||||
minimum_backup_age: 1435
|
||||
random_delay_before_backup: 200
|
||||
upload_speed: 100 Mib
|
||||
download_speed: 0 Mib
|
||||
backend_connections: 0
|
||||
|
|
Loading…
Add table
Reference in a new issue