Spaces:
Running
Running
fix backup status display, sync loop safety, and startup log noise
Browse files- paperclip-sync.py: write explicit status+message fields in sync_to_backup
and sync_from_backup (previously relied on compat shim which mapped
last_errorβmessage, causing empty message on success and duplicate
"Last sync" lines in dashboard)
- paperclip-sync.py: change log format to [sync] %(message)s (drop verbose
timestamp/level prefix that cluttered startup restore output)
- start.sh: sanitize SYNC_INTERVAL (strip non-digits, clamp β₯60s) to
prevent sleep "" failure causing tight spin loop
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- paperclip-sync.py +19 -6
- start.sh +4 -1
paperclip-sync.py
CHANGED
|
@@ -32,7 +32,7 @@ huggingface_hub.utils.disable_progress_bars()
|
|
| 32 |
# Logging: WARNING level keeps errors visible, suppresses routine INFO chatter
|
| 33 |
logging.basicConfig(
|
| 34 |
level=logging.WARNING,
|
| 35 |
-
format='
|
| 36 |
)
|
| 37 |
logger = logging.getLogger(__name__)
|
| 38 |
# Set our own logger to INFO so backup/restore start+finish lines still print
|
|
@@ -490,16 +490,16 @@ def sync_to_backup() -> bool:
|
|
| 490 |
# Step 1: Backup database
|
| 491 |
dump_file, success = backup_database()
|
| 492 |
if not success or not dump_file:
|
| 493 |
-
status
|
| 494 |
-
|
| 495 |
write_status(status)
|
| 496 |
return False
|
| 497 |
|
| 498 |
# Step 2: Create tarball
|
| 499 |
tarball_file, success = create_backup_tarball(dump_file)
|
| 500 |
if not success or not tarball_file:
|
| 501 |
-
status
|
| 502 |
-
|
| 503 |
write_status(status)
|
| 504 |
return False
|
| 505 |
|
|
@@ -507,10 +507,13 @@ def sync_to_backup() -> bool:
|
|
| 507 |
success = sync_to_hf(tarball_file)
|
| 508 |
|
| 509 |
# Update status
|
| 510 |
-
|
|
|
|
| 511 |
status['db_status'] = 'connected' if success else 'error'
|
| 512 |
status['last_error'] = None if success else 'Upload failed'
|
| 513 |
status['sync_count'] = status.get('sync_count', 0) + 1
|
|
|
|
|
|
|
| 514 |
|
| 515 |
write_status(status)
|
| 516 |
|
|
@@ -526,6 +529,8 @@ def sync_to_backup() -> bool:
|
|
| 526 |
logger.error(f'Backup operation failed: {e}')
|
| 527 |
status['last_error'] = str(e)
|
| 528 |
status['db_status'] = 'error'
|
|
|
|
|
|
|
| 529 |
write_status(status)
|
| 530 |
return False
|
| 531 |
|
|
@@ -542,18 +547,24 @@ def sync_from_backup() -> bool:
|
|
| 542 |
# No backup exists yet (first boot) β not an error
|
| 543 |
status['db_status'] = 'connected'
|
| 544 |
status['last_error'] = None
|
|
|
|
|
|
|
| 545 |
write_status(status)
|
| 546 |
logger.info('No prior backup β fresh instance')
|
| 547 |
return True
|
| 548 |
elif success:
|
| 549 |
status['db_status'] = 'connected'
|
| 550 |
status['last_error'] = None
|
|
|
|
|
|
|
| 551 |
write_status(status)
|
| 552 |
logger.info('Restore OK')
|
| 553 |
return True
|
| 554 |
else:
|
| 555 |
status['db_status'] = 'error'
|
| 556 |
status['last_error'] = 'Restore failed'
|
|
|
|
|
|
|
| 557 |
write_status(status)
|
| 558 |
logger.warning('Restore operation failed')
|
| 559 |
return False
|
|
@@ -562,6 +573,8 @@ def sync_from_backup() -> bool:
|
|
| 562 |
logger.error(f'Restore operation failed: {e}')
|
| 563 |
status['last_error'] = str(e)
|
| 564 |
status['db_status'] = 'error'
|
|
|
|
|
|
|
| 565 |
write_status(status)
|
| 566 |
return False
|
| 567 |
|
|
|
|
| 32 |
# Logging: WARNING level keeps errors visible, suppresses routine INFO chatter
|
| 33 |
logging.basicConfig(
|
| 34 |
level=logging.WARNING,
|
| 35 |
+
format='[sync] %(message)s'
|
| 36 |
)
|
| 37 |
logger = logging.getLogger(__name__)
|
| 38 |
# Set our own logger to INFO so backup/restore start+finish lines still print
|
|
|
|
| 490 |
# Step 1: Backup database
|
| 491 |
dump_file, success = backup_database()
|
| 492 |
if not success or not dump_file:
|
| 493 |
+
status.update({'last_error': 'Database backup failed', 'db_status': 'error',
|
| 494 |
+
'status': 'error', 'message': 'Backup failed: pg_dump error'})
|
| 495 |
write_status(status)
|
| 496 |
return False
|
| 497 |
|
| 498 |
# Step 2: Create tarball
|
| 499 |
tarball_file, success = create_backup_tarball(dump_file)
|
| 500 |
if not success or not tarball_file:
|
| 501 |
+
status.update({'last_error': 'Tarball creation failed', 'db_status': 'error',
|
| 502 |
+
'status': 'error', 'message': 'Backup failed: tarball too large or I/O error'})
|
| 503 |
write_status(status)
|
| 504 |
return False
|
| 505 |
|
|
|
|
| 507 |
success = sync_to_hf(tarball_file)
|
| 508 |
|
| 509 |
# Update status
|
| 510 |
+
ts = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
|
| 511 |
+
status['last_sync_time'] = ts
|
| 512 |
status['db_status'] = 'connected' if success else 'error'
|
| 513 |
status['last_error'] = None if success else 'Upload failed'
|
| 514 |
status['sync_count'] = status.get('sync_count', 0) + 1
|
| 515 |
+
status['status'] = 'success' if success else 'error'
|
| 516 |
+
status['message'] = 'Backup uploaded to HF Dataset' if success else 'Upload to HF Dataset failed'
|
| 517 |
|
| 518 |
write_status(status)
|
| 519 |
|
|
|
|
| 529 |
logger.error(f'Backup operation failed: {e}')
|
| 530 |
status['last_error'] = str(e)
|
| 531 |
status['db_status'] = 'error'
|
| 532 |
+
status['status'] = 'error'
|
| 533 |
+
status['message'] = f'Backup error: {e}'
|
| 534 |
write_status(status)
|
| 535 |
return False
|
| 536 |
|
|
|
|
| 547 |
# No backup exists yet (first boot) β not an error
|
| 548 |
status['db_status'] = 'connected'
|
| 549 |
status['last_error'] = None
|
| 550 |
+
status['status'] = 'configured'
|
| 551 |
+
status['message'] = 'Fresh instance β no prior backup'
|
| 552 |
write_status(status)
|
| 553 |
logger.info('No prior backup β fresh instance')
|
| 554 |
return True
|
| 555 |
elif success:
|
| 556 |
status['db_status'] = 'connected'
|
| 557 |
status['last_error'] = None
|
| 558 |
+
status['status'] = 'restored'
|
| 559 |
+
status['message'] = 'Restored from HF Dataset'
|
| 560 |
write_status(status)
|
| 561 |
logger.info('Restore OK')
|
| 562 |
return True
|
| 563 |
else:
|
| 564 |
status['db_status'] = 'error'
|
| 565 |
status['last_error'] = 'Restore failed'
|
| 566 |
+
status['status'] = 'error'
|
| 567 |
+
status['message'] = 'Restore from HF Dataset failed'
|
| 568 |
write_status(status)
|
| 569 |
logger.warning('Restore operation failed')
|
| 570 |
return False
|
|
|
|
| 573 |
logger.error(f'Restore operation failed: {e}')
|
| 574 |
status['last_error'] = str(e)
|
| 575 |
status['db_status'] = 'error'
|
| 576 |
+
status['status'] = 'error'
|
| 577 |
+
status['message'] = f'Restore error: {e}'
|
| 578 |
write_status(status)
|
| 579 |
return False
|
| 580 |
|
start.sh
CHANGED
|
@@ -17,7 +17,10 @@ export PAPERCLIP_CONFIG="${PAPERCLIP_CONFIG:-${PAPERCLIP_HOME}/instances/default
|
|
| 17 |
export PAPERCLIP_TELEMETRY_DISABLED="${PAPERCLIP_TELEMETRY_DISABLED:-1}"
|
| 18 |
export DO_NOT_TRACK="${DO_NOT_TRACK:-1}"
|
| 19 |
export OPENCODE_ALLOW_ALL_MODELS="${OPENCODE_ALLOW_ALL_MODELS:-true}"
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
| 21 |
export SYNC_MAX_FILE_BYTES="${SYNC_MAX_FILE_BYTES:-52428800}"
|
| 22 |
export BACKUP_DATASET_NAME="${BACKUP_DATASET_NAME:-huggingclip-backup}"
|
| 23 |
|
|
|
|
| 17 |
export PAPERCLIP_TELEMETRY_DISABLED="${PAPERCLIP_TELEMETRY_DISABLED:-1}"
|
| 18 |
export DO_NOT_TRACK="${DO_NOT_TRACK:-1}"
|
| 19 |
export OPENCODE_ALLOW_ALL_MODELS="${OPENCODE_ALLOW_ALL_MODELS:-true}"
|
| 20 |
+
# Sanitize: strip non-digits, clamp minimum to 60s to prevent spin loops.
|
| 21 |
+
SYNC_INTERVAL=$(printf '%s' "${SYNC_INTERVAL:-3600}" | tr -dc '0-9')
|
| 22 |
+
{ [ -z "${SYNC_INTERVAL}" ] || [ "${SYNC_INTERVAL}" -lt 60 ]; } && SYNC_INTERVAL=3600
|
| 23 |
+
export SYNC_INTERVAL
|
| 24 |
export SYNC_MAX_FILE_BYTES="${SYNC_MAX_FILE_BYTES:-52428800}"
|
| 25 |
export BACKUP_DATASET_NAME="${BACKUP_DATASET_NAME:-huggingclip-backup}"
|
| 26 |
|