Spaces:
Running
Running
fix backup status display, sync loop spin, and PM2 log leakage
Browse files- postiz-sync.py: cmd_sync/cmd_restore now write status+message fields
alongside db_status so dashboard can show BACKUP: SUCCESS/ERROR/RESTORED
(previously only db_status was written; dashboard reads status/message)
- start.sh: sanitize SYNC_INTERVAL (strip non-digits, clamp β₯60s) to
prevent sleep "" failure causing tight infinite sync loop at startup
- start.sh: extend PM2 grep filter to drop backslash ASCII art (\\{4,}),
PM2 log headers (/root/.pm2/...log last N lines), and > pm2 command echoes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- postiz-sync.py +18 -8
- start.sh +7 -3
postiz-sync.py
CHANGED
|
@@ -450,17 +450,22 @@ def cmd_sync() -> bool:
|
|
| 450 |
try:
|
| 451 |
dump, ok = backup_database()
|
| 452 |
if not ok:
|
| 453 |
-
status.update({"last_error": "pg_dump failed", "db_status": "error"
|
|
|
|
| 454 |
write_status(status); return False
|
| 455 |
tarball, ok = create_backup_tarball(dump)
|
| 456 |
if not ok:
|
| 457 |
-
status.update({"last_error": "tarball creation failed β backup too large or I/O error (check logs)", "db_status": "error"
|
|
|
|
| 458 |
write_status(status); return False
|
| 459 |
ok = upload_to_hf(tarball)
|
| 460 |
-
|
|
|
|
| 461 |
status["db_status"] = "connected" if ok else "error"
|
| 462 |
status["last_error"] = None if ok else "Upload failed"
|
| 463 |
status["sync_count"] = status.get("sync_count", 0) + 1
|
|
|
|
|
|
|
| 464 |
write_status(status)
|
| 465 |
logger.info("Backup synced OK" if ok else "Backup sync failed")
|
| 466 |
if ok:
|
|
@@ -468,7 +473,8 @@ def cmd_sync() -> bool:
|
|
| 468 |
return ok
|
| 469 |
except Exception as e:
|
| 470 |
logger.error(f"Backup operation failed: {e}")
|
| 471 |
-
status.update({"last_error": str(e), "db_status": "error"
|
|
|
|
| 472 |
write_status(status)
|
| 473 |
return False
|
| 474 |
|
|
@@ -479,21 +485,25 @@ def cmd_restore() -> bool:
|
|
| 479 |
try:
|
| 480 |
result = download_and_restore()
|
| 481 |
if result is None:
|
| 482 |
-
status.update({"db_status": "connected", "last_error": None
|
|
|
|
| 483 |
write_status(status)
|
| 484 |
logger.info("No prior backup β fresh instance")
|
| 485 |
return True
|
| 486 |
if result:
|
| 487 |
-
status.update({"db_status": "connected", "last_error": None
|
|
|
|
| 488 |
write_status(status)
|
| 489 |
logger.info("Restore OK")
|
| 490 |
return True
|
| 491 |
-
status.update({"db_status": "error", "last_error": "Restore failed"
|
|
|
|
| 492 |
write_status(status)
|
| 493 |
return False
|
| 494 |
except Exception as e:
|
| 495 |
logger.error(f"Restore operation failed: {e}")
|
| 496 |
-
status.update({"last_error": str(e), "db_status": "error"
|
|
|
|
| 497 |
write_status(status)
|
| 498 |
return False
|
| 499 |
|
|
|
|
| 450 |
try:
|
| 451 |
dump, ok = backup_database()
|
| 452 |
if not ok:
|
| 453 |
+
status.update({"last_error": "pg_dump failed", "db_status": "error",
|
| 454 |
+
"status": "error", "message": "Backup failed: pg_dump error"})
|
| 455 |
write_status(status); return False
|
| 456 |
tarball, ok = create_backup_tarball(dump)
|
| 457 |
if not ok:
|
| 458 |
+
status.update({"last_error": "tarball creation failed β backup too large or I/O error (check logs)", "db_status": "error",
|
| 459 |
+
"status": "error", "message": "Backup failed: tarball too large or I/O error"})
|
| 460 |
write_status(status); return False
|
| 461 |
ok = upload_to_hf(tarball)
|
| 462 |
+
ts = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
| 463 |
+
status["last_sync_time"] = ts
|
| 464 |
status["db_status"] = "connected" if ok else "error"
|
| 465 |
status["last_error"] = None if ok else "Upload failed"
|
| 466 |
status["sync_count"] = status.get("sync_count", 0) + 1
|
| 467 |
+
status["status"] = "success" if ok else "error"
|
| 468 |
+
status["message"] = f"Last synced: {ts}" if ok else "Upload to HF Dataset failed"
|
| 469 |
write_status(status)
|
| 470 |
logger.info("Backup synced OK" if ok else "Backup sync failed")
|
| 471 |
if ok:
|
|
|
|
| 473 |
return ok
|
| 474 |
except Exception as e:
|
| 475 |
logger.error(f"Backup operation failed: {e}")
|
| 476 |
+
status.update({"last_error": str(e), "db_status": "error",
|
| 477 |
+
"status": "error", "message": f"Backup error: {e}"})
|
| 478 |
write_status(status)
|
| 479 |
return False
|
| 480 |
|
|
|
|
| 485 |
try:
|
| 486 |
result = download_and_restore()
|
| 487 |
if result is None:
|
| 488 |
+
status.update({"db_status": "connected", "last_error": None,
|
| 489 |
+
"status": "configured", "message": "Fresh instance β no prior backup"})
|
| 490 |
write_status(status)
|
| 491 |
logger.info("No prior backup β fresh instance")
|
| 492 |
return True
|
| 493 |
if result:
|
| 494 |
+
status.update({"db_status": "connected", "last_error": None,
|
| 495 |
+
"status": "restored", "message": "Restored from HF Dataset"})
|
| 496 |
write_status(status)
|
| 497 |
logger.info("Restore OK")
|
| 498 |
return True
|
| 499 |
+
status.update({"db_status": "error", "last_error": "Restore failed",
|
| 500 |
+
"status": "error", "message": "Restore from HF Dataset failed"})
|
| 501 |
write_status(status)
|
| 502 |
return False
|
| 503 |
except Exception as e:
|
| 504 |
logger.error(f"Restore operation failed: {e}")
|
| 505 |
+
status.update({"last_error": str(e), "db_status": "error",
|
| 506 |
+
"status": "error", "message": f"Restore error: {e}"})
|
| 507 |
write_status(status)
|
| 508 |
return False
|
| 509 |
|
start.sh
CHANGED
|
@@ -86,7 +86,10 @@ export NODE_ENV="${NODE_ENV:-production}"
|
|
| 86 |
export NOT_SECURED="${NOT_SECURED:-true}"
|
| 87 |
|
| 88 |
# Sync config
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
|
|
@@ -293,8 +296,9 @@ cd "${POSTIZ_DIR}"
|
|
| 293 |
-e 'Packages: \+[0-9]|^\+\+\+|preinstall\$|preinstall: Done' \
|
| 294 |
-e 'Scope: [0-9]+ of|Progress: resolved|\(Use --lines' \
|
| 295 |
-e '^apps/(frontend|backend|cron|workers) pm2:' \
|
| 296 |
-
-e '^> gitroom@|^> postiz-[a-z]|^> pnpm (dlx|run)|^> dotenv' \
|
| 297 |
-
-e '[ββββββ€βββΌ]|_\\/+_|\-{10,}' \
|
|
|
|
| 298 |
-e '^[[:space:]]*$' \
|
| 299 |
| sed 's/^/[postiz] /' ) &
|
| 300 |
POSTIZ_PID=$!
|
|
|
|
| 86 |
export NOT_SECURED="${NOT_SECURED:-true}"
|
| 87 |
|
| 88 |
# Sync config
|
| 89 |
+
# Sanitize: strip non-digits, clamp minimum to 60s to prevent spin loops.
|
| 90 |
+
SYNC_INTERVAL=$(printf '%s' "${SYNC_INTERVAL:-3600}" | tr -dc '0-9')
|
| 91 |
+
{ [ -z "${SYNC_INTERVAL}" ] || [ "${SYNC_INTERVAL}" -lt 60 ]; } && SYNC_INTERVAL=3600
|
| 92 |
+
export SYNC_INTERVAL
|
| 93 |
export SYNC_MAX_FILE_BYTES="${SYNC_MAX_FILE_BYTES:-524288000}" # 500 MB (default; covers .next + DB + uploads)
|
| 94 |
export BACKUP_DATASET_NAME="${BACKUP_DATASET_NAME:-huggingpost-backup}"
|
| 95 |
|
|
|
|
| 296 |
-e 'Packages: \+[0-9]|^\+\+\+|preinstall\$|preinstall: Done' \
|
| 297 |
-e 'Scope: [0-9]+ of|Progress: resolved|\(Use --lines' \
|
| 298 |
-e '^apps/(frontend|backend|cron|workers) pm2:' \
|
| 299 |
+
-e '^> gitroom@|^> postiz-[a-z]|^> pnpm (dlx|run)|^> dotenv|^> pm2 ' \
|
| 300 |
+
-e '[ββββββ€βββΌ]|_\\/+_|\-{10,}|\\{4,}' \
|
| 301 |
+
-e '/root/\.pm2/.*\.log last [0-9]' \
|
| 302 |
-e '^[[:space:]]*$' \
|
| 303 |
| sed 's/^/[postiz] /' ) &
|
| 304 |
POSTIZ_PID=$!
|