33import threading
44from datetime import datetime as dt
55from datetime import timedelta
6- from typing import Dict , NamedTuple , Optional , Tuple , Union
6+ from typing import Dict , List , NamedTuple , Optional , Tuple , Union
77
88from packaging import version
99from PyQt6 import QtCore , QtDBus
1919from vorta .i18n import translate
2020from vorta .notifications import VortaNotifications
2121from vorta .store .models import BackupProfileModel , EventLogModel
22- from vorta .utils import borg_compat
22+ from vorta .utils import borg_compat , get_network_status_monitor
2323
2424logger = logging .getLogger (__name__ )
2525
@@ -59,6 +59,13 @@ def __init__(self):
5959 self .qt_timer .setInterval (15 * 60 * 1000 )
6060 self .qt_timer .start ()
6161
62+ # Network backup profiles that are waiting on the network
63+ self .network_deferred_timer = QTimer ()
64+ self .network_deferred_timer .timeout .connect (self .create_backup_if_net_up )
65+ self .network_deferred_timer .setInterval (5 * 1000 ) # Short interval for the network to come up
66+ # Don't start until its actually needed
67+ self .network_deferred_profiles : List [str ] = []
68+
6269 # connect signals
6370 self .app .backup_finished_event .connect (lambda res : self .set_timer_for_profile (res ['params' ]['profile_id' ]))
6471
@@ -81,6 +88,27 @@ def loginSuspendNotify(self, suspend: bool):
8188 logger .debug ("Got login suspend/resume notification" )
8289 self .reload_all_timers ()
8390
91+ def create_backup_if_net_up (self ):
92+ nm = get_network_status_monitor ()
93+ if nm .is_network_active ():
94+ # Cancel the timer
95+ self .network_deferred_timer .stop ()
96+ logger .info ("the network is active, dispatching waiting jobs" )
97+ # create_backup will add to waiting_network if the network goes down again
98+ # flip ahead of time here in case that happens
99+ waiting = self .network_deferred_profiles
100+ self .network_deferred_profiles = []
101+ for profile_id in waiting :
102+ self .create_backup (profile_id )
103+ else :
104+ logger .debug ("there are jobs waiting on the network, but it is not yet up" )
105+
106+ def defer_backup (self , profile_id ):
107+ if not self .network_deferred_profiles :
108+ # Nothing is currently waiting so start the timer
109+ self .network_deferred_timer .start ()
110+ self .network_deferred_profiles .append (profile_id )
111+
84112 def tr (self , * args , ** kwargs ):
85113 scope = self .__class__ .__name__
86114 return translate (scope , * args , ** kwargs )
@@ -397,6 +425,15 @@ def create_backup(self, profile_id):
397425 logger .info ('Profile not found. Maybe deleted?' )
398426 return
399427
428+ if profile .repo .is_remote_repo () and not get_network_status_monitor ().is_network_active ():
429+ logger .info (
430+ 'repo %s is remote and there is no active network connection, deferring backup for %s' ,
431+ profile .repo .name ,
432+ profile .name ,
433+ )
434+ self .defer_backup (profile_id )
435+ return
436+
400437 # Skip if a job for this profile (repo) is already in progress
401438 if self .app .jobs_manager .is_worker_running (site = profile .repo .id ):
402439 logger .debug ('A job for repo %s is already active.' , profile .repo .id )
@@ -521,6 +558,12 @@ def post_backup_tasks(self, profile_id):
521558 )
522559
523560 def remove_job (self , profile_id ):
561+ if profile_id in self .network_deferred_profiles :
562+ self .network_deferred_profiles .remove (profile_id )
563+ # If nothing is waiting cancel the timer
564+ if not self .network_deferred_profiles :
565+ self .network_deferred_timer .stop ()
566+
524567 if profile_id in self .timers :
525568 qtimer = self .timers [profile_id ].get ('qtt' )
526569 if qtimer is not None :
0 commit comments