Skip to content

fix: backup command executes database dump twice, wasting resources and risking data loss #4222

@kuishou68

Description

@kuishou68

Problem

In packages/server/src/utils/backups/utils.ts, the getBackupCommand function generates a shell script that runs the database dump command (${backupCommand}) twice:

# First execution: "test" — output discarded
BACKUP_OUTPUT=$(${backupCommand} 2>&1 >/dev/null) || {
    echo "[$(date)] ❌ Error: Backup failed"
    exit 1;
}

# Second execution: actual upload — output piped to rclone
UPLOAD_OUTPUT=$(${backupCommand} | ${rcloneCommand} 2>&1 >/dev/null) || {
    echo "[$(date)] ❌ Error: Upload to S3 failed"
    exit 1;
}

This means every backup operation performs the database dump twice:

  1. The first run dumps the entire database but discards the output (just to check if the command succeeds)
  2. The second run dumps the database again and pipes it to rclone for upload

Impact

  • Performance: Every backup takes double the time and puts double the load on the database server
  • Inconsistency: The two dumps may capture different database states if writes occur between them (the uploaded backup may differ from the "verified" backup)
  • Error handling gap: The success check (BACKUP_OUTPUT) validates a dump that is never uploaded; the actual upload (UPLOAD_OUTPUT) runs a completely new dump without the pre-validation
  • Large databases: For large databases, the doubled dump can cause significant timeout and memory pressure

Expected

The database dump should run exactly once, with its output piped directly into rclone for upload. Success/failure is determined by the combined exit code of the pipeline.

Fix

Remove the redundant first execution and pipe the single backup output directly to rclone:

# Remove the BACKUP_OUTPUT test block entirely
# Keep only the combined pipeline:
UPLOAD_OUTPUT=$(${backupCommand} | ${rcloneCommand} 2>&1) || {
    echo "[$(date)] ❌ Error: Backup or upload failed" >> ${logPath};
    echo "Error: $UPLOAD_OUTPUT" >> ${logPath};
    exit 1;
}

This runs the dump exactly once, pipes it to rclone in a single streaming operation, and correctly captures any errors from either the dump or the upload step.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions