Skip to content

Commit 73eec35

Browse files
More fixes
1 parent 8206f3b commit 73eec35

File tree

2 files changed

+60
-11
lines changed

2 files changed

+60
-11
lines changed

app.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,24 @@ def schedule_all_repositories():
198198
except Exception as e:
199199
logger.error(f"Error scheduling repositories on startup: {e}")
200200

201-
# Flag to ensure we only initialize once
201+
# Thread-safe flag to ensure we only initialize once
202+
import threading
203+
_scheduler_lock = threading.Lock()
202204
_scheduler_initialized = False
203205

204206
def ensure_scheduler_initialized():
205-
"""Ensure scheduler is initialized with existing repositories"""
207+
"""Ensure scheduler is initialized with existing repositories (thread-safe)"""
206208
global _scheduler_initialized
207-
if not _scheduler_initialized:
208-
schedule_all_repositories()
209-
_scheduler_initialized = True
209+
if _scheduler_initialized:
210+
return
211+
212+
with _scheduler_lock:
213+
# Double-check pattern to avoid race conditions
214+
if not _scheduler_initialized:
215+
logger.info("Initializing scheduler with existing repositories...")
216+
schedule_all_repositories()
217+
_scheduler_initialized = True
218+
logger.info("Scheduler initialization completed")
210219

211220
@login_manager.user_loader
212221
def load_user(user_id):
@@ -215,7 +224,6 @@ def load_user(user_id):
215224
@app.route('/')
216225
@login_required
217226
def dashboard():
218-
ensure_scheduler_initialized()
219227
repositories = Repository.query.filter_by(user_id=current_user.id).all()
220228
recent_jobs = BackupJob.query.filter_by(user_id=current_user.id).order_by(BackupJob.created_at.desc()).limit(10).all()
221229
return render_template('dashboard.html', repositories=repositories, recent_jobs=recent_jobs)
@@ -647,14 +655,15 @@ def backup_with_context():
647655
).first()
648656

649657
if running_job:
650-
logger.warning(f"Backup already running for repository {repo.name}, skipping")
658+
logger.warning(f"Backup already running for repository {repo.name} (job {running_job.id}), skipping")
651659
return
652660

653-
# Additional check: ensure no backup started in the last 5 minutes to prevent rapid duplicates
661+
# Additional check: ensure no backup started in the last 30 seconds to prevent rapid duplicates
662+
recent_cutoff = datetime.utcnow() - timedelta(seconds=30)
654663
recent_backup = BackupJob.query.filter_by(
655664
repository_id=repository.id
656665
).filter(
657-
BackupJob.started_at > datetime.utcnow() - timedelta(minutes=5)
666+
BackupJob.started_at > recent_cutoff
658667
).first()
659668

660669
if recent_backup:
@@ -754,5 +763,15 @@ def backup_with_context():
754763
else:
755764
logger.error(f"Failed to schedule job {job_id}")
756765

766+
# Initialize scheduler with existing repositories at startup
767+
# This runs after all functions are defined
768+
try:
769+
with app.app_context():
770+
logger.info("Starting scheduler initialization at app startup...")
771+
ensure_scheduler_initialized()
772+
logger.info("Scheduler initialization at startup completed")
773+
except Exception as e:
774+
logger.error(f"Failed to initialize scheduler at startup: {e}")
775+
757776
if __name__ == '__main__':
758777
app.run(host='0.0.0.0', port=8080, debug=False)

backup_service.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import zipfile
55
import tarfile
66
import logging
7-
from datetime import datetime
7+
from datetime import datetime, timedelta
88
from pathlib import Path
99
from github import Github
1010
from models import db, BackupJob
@@ -21,6 +21,28 @@ def backup_repository(self, repository):
2121
"""Backup a repository according to its settings"""
2222
logger.info(f"Starting backup for repository: {repository.name}")
2323

24+
# Check if there's already a running backup for this repository
25+
existing_running_job = BackupJob.query.filter_by(
26+
repository_id=repository.id,
27+
status='running'
28+
).first()
29+
30+
if existing_running_job:
31+
logger.warning(f"Backup already running for repository {repository.name} (job {existing_running_job.id}), skipping")
32+
return
33+
34+
# Also check for very recent backups (within last 30 seconds) to prevent rapid duplicates
35+
recent_cutoff = datetime.utcnow() - timedelta(seconds=30)
36+
recent_job = BackupJob.query.filter_by(
37+
repository_id=repository.id
38+
).filter(
39+
BackupJob.started_at > recent_cutoff
40+
).first()
41+
42+
if recent_job:
43+
logger.warning(f"Very recent backup found for repository {repository.name} (started at {recent_job.started_at}), skipping to prevent duplicates")
44+
return
45+
2446
# Create backup job record
2547
backup_job = BackupJob(
2648
user_id=repository.user_id,
@@ -29,7 +51,15 @@ def backup_repository(self, repository):
2951
started_at=datetime.utcnow()
3052
)
3153
db.session.add(backup_job)
32-
db.session.commit()
54+
55+
# Commit immediately to make this job visible to other processes/threads
56+
try:
57+
db.session.commit()
58+
logger.info(f"Created backup job {backup_job.id} for repository {repository.name}")
59+
except Exception as e:
60+
logger.error(f"Failed to commit backup job creation: {e}")
61+
db.session.rollback()
62+
return
3363

3464
temp_clone_dir = None
3565
try:

0 commit comments

Comments
 (0)