somratpro commited on
Commit
264b68d
Β·
1 Parent(s): e47c28d

refactor: implement two-pass backup creation to automatically exclude frontend cache if tarball exceeds size limits

Browse files
Files changed (2) hide show
  1. postiz-sync.py +35 -17
  2. start.sh +1 -1
postiz-sync.py CHANGED
@@ -149,37 +149,55 @@ def _exclude_next_cache(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo | None:
149
  return tarinfo
150
 
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  def create_backup_tarball(dump_file: str) -> tuple[str | None, bool]:
153
  temp_dir = tempfile.mkdtemp()
154
  tarball = Path(temp_dir) / "huggingpost-backup.tar.gz"
155
  try:
156
- with tarfile.open(tarball, "w:gz") as tar:
157
- tar.add(dump_file, arcname="postiz.sql")
158
- if UPLOADS_DIR.exists():
159
- tar.add(str(UPLOADS_DIR), arcname="uploads")
160
- if SECRETS_DIR.exists():
161
- tar.add(str(SECRETS_DIR), arcname=".secrets")
162
- # Include compiled frontend so subsequent restarts skip the 5-min build.
163
- # Exclude .next/cache (webpack cache) β€” large and not needed to run.
164
- if NEXT_DIR.exists() and (NEXT_DIR / "BUILD_ID").exists():
165
- tar.add(str(NEXT_DIR), arcname="frontend-next", filter=_exclude_next_cache)
166
- logger.debug("Included .next in tarball (webpack cache excluded)")
167
  size = tarball.stat().st_size
168
  size_mb = size / 1024 / 1024
169
  logger.debug(f"Tarball created ({size_mb:.2f} MB)")
170
  if size > SYNC_MAX_FILE_BYTES:
171
- logger.error(
172
- f"Backup too large: {size_mb:.0f} MB > {SYNC_MAX_FILE_BYTES/1024/1024:.0f} MB. "
173
- "Move uploads to Cloudflare R2 (set STORAGE_PROVIDER=cloudflare) "
174
- "or raise SYNC_MAX_FILE_BYTES."
175
  )
176
- return None, False
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  return str(tarball), True
178
  except Exception as e:
179
  logger.error(f"Failed to create tarball: {e}")
180
  return None, False
181
 
182
 
 
183
  def upload_to_hf(backup_file: str) -> bool:
184
  if not HF_TOKEN:
185
  logger.warning("HF_TOKEN not set β€” skipping upload")
@@ -348,7 +366,7 @@ def cmd_sync() -> bool:
348
  write_status(status); return False
349
  tarball, ok = create_backup_tarball(dump)
350
  if not ok:
351
- status.update({"last_error": "tarball creation failed", "db_status": "error"})
352
  write_status(status); return False
353
  ok = upload_to_hf(tarball)
354
  status["last_sync_time"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
 
149
  return tarinfo
150
 
151
 
152
+ def _write_tarball(tarball: Path, dump_file: str, include_next: bool) -> None:
153
+ """Write the backup tarball. Raises on any error."""
154
+ with tarfile.open(tarball, "w:gz") as tar:
155
+ tar.add(dump_file, arcname="postiz.sql")
156
+ if UPLOADS_DIR.exists():
157
+ tar.add(str(UPLOADS_DIR), arcname="uploads")
158
+ if SECRETS_DIR.exists():
159
+ tar.add(str(SECRETS_DIR), arcname=".secrets")
160
+ if include_next and NEXT_DIR.exists() and (NEXT_DIR / "BUILD_ID").exists():
161
+ tar.add(str(NEXT_DIR), arcname="frontend-next", filter=_exclude_next_cache)
162
+ logger.debug("Included .next in tarball (webpack cache excluded)")
163
+
164
+
165
  def create_backup_tarball(dump_file: str) -> tuple[str | None, bool]:
166
  temp_dir = tempfile.mkdtemp()
167
  tarball = Path(temp_dir) / "huggingpost-backup.tar.gz"
168
  try:
169
+ # First attempt: include compiled .next so subsequent restarts skip rebuild.
170
+ _write_tarball(tarball, dump_file, include_next=True)
 
 
 
 
 
 
 
 
 
171
  size = tarball.stat().st_size
172
  size_mb = size / 1024 / 1024
173
  logger.debug(f"Tarball created ({size_mb:.2f} MB)")
174
  if size > SYNC_MAX_FILE_BYTES:
175
+ logger.warning(
176
+ f"Tarball with .next too large ({size_mb:.0f} MB > "
177
+ f"{SYNC_MAX_FILE_BYTES/1024/1024:.0f} MB limit) β€” "
178
+ "retrying without compiled frontend..."
179
  )
180
+ # Second attempt: skip .next, keep essential DB + uploads + secrets.
181
+ tarball.unlink(missing_ok=True)
182
+ _write_tarball(tarball, dump_file, include_next=False)
183
+ size = tarball.stat().st_size
184
+ size_mb = size / 1024 / 1024
185
+ logger.debug(f"Tarball without .next: {size_mb:.2f} MB")
186
+ if size > SYNC_MAX_FILE_BYTES:
187
+ logger.error(
188
+ f"Backup still too large without .next ({size_mb:.0f} MB > "
189
+ f"{SYNC_MAX_FILE_BYTES/1024/1024:.0f} MB). "
190
+ "Move uploads to Cloudflare R2 (STORAGE_PROVIDER=cloudflare) "
191
+ "or raise SYNC_MAX_FILE_BYTES."
192
+ )
193
+ return None, False
194
  return str(tarball), True
195
  except Exception as e:
196
  logger.error(f"Failed to create tarball: {e}")
197
  return None, False
198
 
199
 
200
+
201
  def upload_to_hf(backup_file: str) -> bool:
202
  if not HF_TOKEN:
203
  logger.warning("HF_TOKEN not set β€” skipping upload")
 
366
  write_status(status); return False
367
  tarball, ok = create_backup_tarball(dump)
368
  if not ok:
369
+ status.update({"last_error": "tarball creation failed β€” backup too large or I/O error (check logs)", "db_status": "error"})
370
  write_status(status); return False
371
  ok = upload_to_hf(tarball)
372
  status["last_sync_time"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
start.sh CHANGED
@@ -87,7 +87,7 @@ export NOT_SECURED="${NOT_SECURED:-true}"
87
 
88
  # Sync config
89
  export SYNC_INTERVAL="${SYNC_INTERVAL:-300}"
90
- export SYNC_MAX_FILE_BYTES="${SYNC_MAX_FILE_BYTES:-104857600}"
91
  export BACKUP_DATASET_NAME="${BACKUP_DATASET_NAME:-huggingpost-backup}"
92
 
93
  # ── Banner ───────────────────────────────────────────────────────────────────
 
87
 
88
  # Sync config
89
  export SYNC_INTERVAL="${SYNC_INTERVAL:-300}"
90
+ export SYNC_MAX_FILE_BYTES="${SYNC_MAX_FILE_BYTES:-524288000}" # 500 MB (default; covers .next + DB + uploads)
91
  export BACKUP_DATASET_NAME="${BACKUP_DATASET_NAME:-huggingpost-backup}"
92
 
93
  # ── Banner ───────────────────────────────────────────────────────────────────