Skip to main content

Backup and Restore

Scheduler0 provides built-in database backup and restore capabilities using SQLite's Online Backup API. This allows you to safely backup and restore your database even while the cluster is running.

Overview

The backup/restore feature provides:

  • Automatic timestamped backups - Create backups with automatic naming
  • Custom path backups - Backup to a specific file path
  • Database restore - Restore from any backup file
  • Real-time progress tracking - Monitor backup/restore operations
  • Leader-only operations - Ensures consistency by restricting to leader node
  • Safe concurrent access - Uses SQLite Online Backup API for safe operation

API Endpoints

Start Automatic Backup

Initiates a backup with an automatic timestamped filename.

POST /api/v1/cluster/backup

Response (202 Accepted):

{
"success": true,
"data": {
"status": "backup initiated"
}
}

Backup to Specific File

Initiates a backup to a specific destination path.

POST /api/v1/cluster/backup-to-file
Content-Type: application/json

{
"destPath": "/path/to/backup-20260113-143000.db"
}

Response (202 Accepted):

{
"success": true,
"data": {
"status": "backup to file initiated"
}
}

Restore from Backup

Initiates a restore from a backup file.

POST /api/v1/cluster/restore
Content-Type: application/json

{
"backupPath": "/path/to/backup-20260113-143000.db"
}

Response (202 Accepted):

{
"success": true,
"data": {
"status": "restore initiated"
}
}

Get Progress

Retrieves the current backup/restore progress.

GET /api/v1/cluster/backup-restore-progress

Response (200 OK):

{
"success": true,
"data": {
"operationType": "backup",
"status": "in-progress",
"progress": 45,
"message": "Backing up: 4500/10000 rows (45.0%)",
"startTime": "2026-01-13T14:30:00Z",
"endTime": "0001-01-01T00:00:00Z",
"backupPath": ""
}
}

On completion:

{
"success": true,
"data": {
"operationType": "backup",
"status": "completed",
"progress": 100,
"message": "Backup completed: /path/to/sqlite_data/backups/db-20260113-143015.db",
"startTime": "2026-01-13T14:30:00Z",
"endTime": "2026-01-13T14:30:15Z",
"backupPath": "/path/to/sqlite_data/backups/db-20260113-143015.db"
}
}

Progress Status Values

  • idle - No operation in progress
  • in-progress - Operation currently running
  • completed - Operation finished successfully
  • failed - Operation failed (check message for error)

Operation Types

  • backup - Automatic timestamped backup
  • backup-to-file - Backup to specific path
  • restore - Database restore

Client SDKs

Go Client

import scheduler0 "github.com/scheduler0/scheduler0-go-client"

// Create client with basic auth (for cluster operations)
client, _ := scheduler0.NewBasicAuthClient(
"http://localhost:7070",
"v1",
"username",
"password",
)

// Start automatic backup
result, err := client.BackupDatabase()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s\n", result.Data["status"])

// Poll for progress
for {
progress, err := client.GetBackupRestoreProgress()
if err != nil {
log.Fatal(err)
}

fmt.Printf("%s: %d%% - %s\n",
progress.Data.OperationType,
progress.Data.Progress,
progress.Data.Message)

if progress.Data.Status == "completed" {
fmt.Printf("Backup path: %s\n", progress.Data.BackupPath)
break
}

if progress.Data.Status == "failed" {
log.Fatal("Backup failed")
}

time.Sleep(2 * time.Second)
}

// Backup to specific file
result, err = client.BackupDatabaseToFile("/path/to/backup.db")

// Restore from backup
result, err = client.RestoreDatabase("/path/to/backup.db")

Node.js Client

import { Client } from 'scheduler0-node-client';

// Create client with basic auth
const client = Client.newBasicAuthClient(
'http://localhost:7070',
'v1',
'username',
'password'
);

// Start automatic backup
const result = await client.backupDatabase();
console.log(`Status: ${result.data.status}`);

// Poll for progress
while (true) {
const progress = await client.getBackupRestoreProgress();

console.log(`${progress.data.operationType}: ${progress.data.progress}% - ${progress.data.message}`);

if (progress.data.status === 'completed') {
console.log(`Backup path: ${progress.data.backupPath}`);
break;
}

if (progress.data.status === 'failed') {
throw new Error('Backup failed');
}

await new Promise(resolve => setTimeout(resolve, 2000));
}

// Backup to specific file
await client.backupDatabaseToFile('/path/to/backup.db');

// Restore from backup
await client.restoreDatabase('/path/to/backup.db');

Python Client

from scheduler0 import Client, backup
import time

# Create client with basic auth
client = Client.NewBasicAuthClient(
"http://localhost:7070",
"v1",
"username",
"password"
)

# Start automatic backup
result = backup.backup_database(client)
print(f"Status: {result['data']['status']}")

# Poll for progress
while True:
progress = backup.get_backup_restore_progress(client)
data = progress['data']

print(f"{data['operationType']}: {data['progress']}% - {data['message']}")

if data['status'] == 'completed':
print(f"Backup path: {data['backupPath']}")
break

if data['status'] == 'failed':
raise Exception('Backup failed')

time.sleep(2)

# Backup to specific file
backup.backup_database_to_file(client, '/path/to/backup.db')

# Restore from backup
backup.restore_database(client, '/path/to/backup.db')

CLI

Start Automatic Backup

scheduler0 backup start

Backup to Specific File

scheduler0 backup to-file /path/to/backup.db

Restore from Backup

scheduler0 backup restore /path/to/backup.db

Check Progress

scheduler0 backup progress

Watch Progress in Real-Time

scheduler0 backup watch

This will continuously poll and display progress until the operation completes:

Watching backup/restore progress (Ctrl+C to stop)...

[14:30:05] backup: 0% - Starting backup...
[14:30:07] backup: 25% - Backing up: 2500/10000 rows (25.0%)
[14:30:09] backup: 50% - Backing up: 5000/10000 rows (50.0%)
[14:30:11] backup: 75% - Backing up: 7500/10000 rows (75.0%)
[14:30:13] backup: 100% - Backup completed: /path/to/sqlite_data/backups/db-20260113-143015.db

Operation finished!
Backup path: /path/to/sqlite_data/backups/db-20260113-143015.db

Backup Location

By default, automatic backups are stored in:

<database-directory>/backups/<database-name>-YYYYMMDD-HHMMSS.db

For example:

/path/to/sqlite_data/backups/db-20260113-143015.db

Best Practices

  1. Regular Backups - Schedule regular backups using cron or similar
  2. Off-site Storage - Copy backups to off-site storage for disaster recovery
  3. Test Restores - Periodically test restore operations to ensure backups are valid
  4. Monitor Progress - Use the progress endpoint to monitor long-running operations
  5. Leader Node - Backup/restore operations are automatically restricted to the leader node
  6. Pre-restore Backup - The system automatically creates a pre-restore backup for safety

Safety Features

  • Pre-restore Backup - Before restoring, the current database is automatically backed up to .pre-restore-backup
  • Atomic Operations - Uses SQLite's Online Backup API for safe, atomic operations
  • Connection Locking - Prevents concurrent database modifications during backup/restore
  • Progress Tracking - Real-time progress updates for monitoring
  • Error Recovery - Failed operations are logged and partial backups are cleaned up

Troubleshooting

Backup Fails to Start

  • Ensure you're authenticated with proper credentials
  • Verify the node is the cluster leader
  • Check disk space availability

Restore Fails

  • Verify the backup file exists and is readable
  • Ensure the backup file is a valid SQLite database
  • Check that no other operations are in progress

Progress Shows "idle"

  • No backup/restore operation has been initiated
  • Previous operation has completed
  • Start a new operation to see progress

Notes

  • Only one backup/restore operation can run at a time
  • Operations are restricted to the leader node for consistency
  • The database remains accessible during backup operations
  • Restore operations temporarily close and reopen the database connection