backup: limit local second-brain retention
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Backup-Task für Second Brain - isoliert, persistent."""
|
"""Backup-Task fuer Second Brain - isoliert, persistent.
|
||||||
|
|
||||||
|
Local retention is intentionally small on the OpenClaw host: keep only the
|
||||||
|
newest two JSONL exports. Longer-term/off-host retention should be handled by
|
||||||
|
an encrypted artifact/package workflow, not by committing raw brain exports to
|
||||||
|
Git.
|
||||||
|
"""
|
||||||
import json, os, sys
|
import json, os, sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
@@ -8,14 +14,47 @@ BRAIN_DIR = Path("/root/.openclaw/workspace/second-brain")
|
|||||||
sys.path.insert(0, str(BRAIN_DIR))
|
sys.path.insert(0, str(BRAIN_DIR))
|
||||||
from src.store import EngramStore
|
from src.store import EngramStore
|
||||||
|
|
||||||
|
DEFAULT_KEEP_LOCAL_BACKUPS = 2
|
||||||
|
|
||||||
|
def backup_sort_key(path: Path) -> tuple[float, str]:
|
||||||
|
return (path.stat().st_mtime, path.name)
|
||||||
|
|
||||||
|
def prune_local_backups(data_dir: Path, keep: int = DEFAULT_KEEP_LOCAL_BACKUPS) -> list[str]:
|
||||||
|
"""Keep only the newest local backup files.
|
||||||
|
|
||||||
|
Both uncompressed `.jsonl` and compressed `.jsonl.gz` exports are counted,
|
||||||
|
so historical compressed backups do not silently accumulate again.
|
||||||
|
"""
|
||||||
|
keep = max(1, keep)
|
||||||
|
backups = sorted(
|
||||||
|
list(data_dir.glob("backup_*.jsonl")) + list(data_dir.glob("backup_*.jsonl.gz")),
|
||||||
|
key=backup_sort_key,
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
removed: list[str] = []
|
||||||
|
for backup in backups[keep:]:
|
||||||
|
backup.unlink()
|
||||||
|
removed.append(str(backup))
|
||||||
|
return removed
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
brain_db = os.environ.get("BRAIN_DB", str(BRAIN_DIR / "data" / "brain.sqlite"))
|
brain_db = os.environ.get("BRAIN_DB", str(BRAIN_DIR / "data" / "brain.sqlite"))
|
||||||
|
keep_local = int(os.environ.get("SECOND_BRAIN_BACKUP_KEEP_LOCAL", str(DEFAULT_KEEP_LOCAL_BACKUPS)))
|
||||||
store = EngramStore(brain_db)
|
store = EngramStore(brain_db)
|
||||||
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
||||||
backup_path = Path(brain_db).parent / f"backup_{ts}.jsonl"
|
backup_path = Path(brain_db).parent / f"backup_{ts}.jsonl"
|
||||||
count = store.export_jsonl(str(backup_path))
|
count = store.export_jsonl(str(backup_path))
|
||||||
result = {"timestamp": datetime.now(timezone.utc).isoformat(), "backup_path": str(backup_path), "count": count, "success": True}
|
removed = prune_local_backups(Path(brain_db).parent, keep_local)
|
||||||
|
result = {
|
||||||
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||||
|
"backup_path": str(backup_path),
|
||||||
|
"count": count,
|
||||||
|
"removed_old_backups": removed,
|
||||||
|
"keep_local": keep_local,
|
||||||
|
"success": True,
|
||||||
|
}
|
||||||
print(f"BACKUP: {count} Engramme -> {backup_path}")
|
print(f"BACKUP: {count} Engramme -> {backup_path}")
|
||||||
|
print(json.dumps(result, ensure_ascii=True))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user