Cyber Catalyst Team commited on
Commit
2488be2
·
1 Parent(s): 24d545a

Fold Space 4 backup daemon loop into backend.py

Browse files
Files changed (1) hide show
  1. backend.py +62 -0
backend.py CHANGED
@@ -15,6 +15,8 @@ The agentic loop:
15
  """
16
 
17
  import os
 
 
18
  import json
19
  import uuid
20
  import subprocess
@@ -54,6 +56,7 @@ NIM_API_KEY = os.environ.get("NVIDIA_NIM_API_KEY", "")
54
  BACKEND_API_KEY = os.environ.get("BACKEND_API_KEY", "")
55
  DATABASE_URL = os.environ.get("DATABASE_URL", "")
56
  WORKSPACE_DIR = os.environ.get("WORKSPACE_DIR", "/tmp/workspace")
 
57
  MAX_TOOL_ROUNDS = int(os.environ.get("MAX_TOOL_ROUNDS", "10"))
58
 
59
  # NIM models that reliably support tool/function calling
@@ -1536,10 +1539,69 @@ async def db_heartbeat_loop():
1536
  await asyncio.sleep(240) # Every 4 minutes
1537
 
1538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1539
  @app.on_event("startup")
1540
  async def startup_event():
1541
  # Start the watchdog thread on startup
1542
  threading.Thread(target=run_watchdog, daemon=True).start()
 
 
1543
  # Start the db keep-alive loop on FastAPI event loop
1544
  asyncio.create_task(db_heartbeat_loop())
1545
  # Start the db nightly retention cleanup loop
 
15
  """
16
 
17
  import os
18
+ import shutil
19
+ import threading
20
  import json
21
  import uuid
22
  import subprocess
 
56
  BACKEND_API_KEY = os.environ.get("BACKEND_API_KEY", "")
57
  DATABASE_URL = os.environ.get("DATABASE_URL", "")
58
  WORKSPACE_DIR = os.environ.get("WORKSPACE_DIR", "/tmp/workspace")
59
+ BACKUP_GIT_REPO = os.environ.get("BACKUP_GIT_REPO", "")
60
  MAX_TOOL_ROUNDS = int(os.environ.get("MAX_TOOL_ROUNDS", "10"))
61
 
62
  # NIM models that reliably support tool/function calling
 
1539
  await asyncio.sleep(240) # Every 4 minutes
1540
 
1541
 
1542
+ def run_backup_loop():
1543
+ log_activity("Local Git Backup Loop started")
1544
+ while True:
1545
+ # Wait 5 minutes between runs
1546
+ time.sleep(300)
1547
+ if not BACKUP_GIT_REPO:
1548
+ continue
1549
+ try:
1550
+ log_activity("[Backup] Starting local workspace backup...")
1551
+ # 1. Clean local backup directory
1552
+ backup_local_dir = "/tmp/git_backup_repo"
1553
+ if os.path.exists(backup_local_dir):
1554
+ shutil.rmtree(backup_local_dir)
1555
+ os.makedirs(backup_local_dir, exist_ok=True)
1556
+
1557
+ # 2. Point-in-time snapshot copy
1558
+ snapshot_dir = "/tmp/workspace_snapshot"
1559
+ if os.path.exists(snapshot_dir):
1560
+ shutil.rmtree(snapshot_dir)
1561
+ shutil.copytree(WORKSPACE_DIR, snapshot_dir, symlinks=True, ignore=shutil.ignore_patterns('.git', 'node_modules', '.next'))
1562
+
1563
+ # 3. Zip snapshot
1564
+ archive_base = "/tmp/workspace_backup_download"
1565
+ archive_zip = archive_base + ".zip"
1566
+ if os.path.exists(archive_zip):
1567
+ os.unlink(archive_zip)
1568
+ shutil.make_archive(archive_base, 'zip', snapshot_dir)
1569
+ shutil.rmtree(snapshot_dir)
1570
+
1571
+ # 4. Handle Split if needed
1572
+ target_dest = os.path.join(backup_local_dir, "workspace_backup.zip")
1573
+ zip_size = os.path.getsize(archive_zip)
1574
+ max_part_size = 50 * 1024 * 1024 # 50MB
1575
+ if zip_size > max_part_size:
1576
+ subprocess.run(f"split -b 50M {archive_zip} {target_dest}.part", shell=True)
1577
+ else:
1578
+ shutil.copy(archive_zip, target_dest)
1579
+ os.unlink(archive_zip)
1580
+
1581
+ # 5. Git commit and force push
1582
+ subprocess.run("git init", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1583
+ subprocess.run("git config user.name 'Backup Agent'", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1584
+ subprocess.run("git config user.email 'backup@agent.internal'", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1585
+ subprocess.run(f"git remote add origin {BACKUP_GIT_REPO}", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1586
+ subprocess.run("git checkout -b main", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1587
+ subprocess.run("git add -A", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1588
+ subprocess.run('git commit -m "Auto-backup: ' + time.strftime("%Y-%m-%d %H:%M:%S") + '"', shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1589
+
1590
+ result = subprocess.run("git push origin main --force", shell=True, cwd=backup_local_dir, stdout=subprocess.DEVNULL)
1591
+ if result.returncode == 0:
1592
+ log_activity("[Backup] Sync completed successfully (git history purged)")
1593
+ else:
1594
+ log_activity("[Backup Error] Git push failed")
1595
+ except Exception as e:
1596
+ log_activity(f"[Backup Error] {e}")
1597
+
1598
+
1599
  @app.on_event("startup")
1600
  async def startup_event():
1601
  # Start the watchdog thread on startup
1602
  threading.Thread(target=run_watchdog, daemon=True).start()
1603
+ # Start the local backup loop thread
1604
+ threading.Thread(target=run_backup_loop, daemon=True).start()
1605
  # Start the db keep-alive loop on FastAPI event loop
1606
  asyncio.create_task(db_heartbeat_loop())
1607
  # Start the db nightly retention cleanup loop