Fix for memory issue during backup
This commit is contained in:
@@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -141,9 +140,12 @@ public class DatabaseManagementService implements ApplicationContextAware {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a comprehensive backup including database and files in ZIP format
|
* Create a comprehensive backup including database and files in ZIP format
|
||||||
|
* Returns a streaming resource to avoid loading large backups into memory
|
||||||
*/
|
*/
|
||||||
public Resource createCompleteBackup() throws SQLException, IOException {
|
public Resource createCompleteBackup() throws SQLException, IOException {
|
||||||
|
// Create temp file with deleteOnExit as safety net
|
||||||
Path tempZip = Files.createTempFile("storycove-backup", ".zip");
|
Path tempZip = Files.createTempFile("storycove-backup", ".zip");
|
||||||
|
tempZip.toFile().deleteOnExit();
|
||||||
|
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(tempZip))) {
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(tempZip))) {
|
||||||
// 1. Add database dump
|
// 1. Add database dump
|
||||||
@@ -156,11 +158,30 @@ public class DatabaseManagementService implements ApplicationContextAware {
|
|||||||
addMetadataToZip(zipOut);
|
addMetadataToZip(zipOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the ZIP file as a resource
|
// Return the ZIP file as a FileSystemResource for streaming
|
||||||
byte[] zipData = Files.readAllBytes(tempZip);
|
// This avoids loading the entire file into memory
|
||||||
|
return new org.springframework.core.io.FileSystemResource(tempZip.toFile()) {
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
// Wrap the input stream to delete the temp file after it's fully read
|
||||||
|
return new java.io.FilterInputStream(super.getInputStream()) {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
super.close();
|
||||||
|
} finally {
|
||||||
|
// Clean up temp file after streaming is complete
|
||||||
|
try {
|
||||||
Files.deleteIfExists(tempZip);
|
Files.deleteIfExists(tempZip);
|
||||||
|
} catch (IOException e) {
|
||||||
return new ByteArrayResource(zipData);
|
// Log but don't fail - deleteOnExit will handle it
|
||||||
|
System.err.println("Warning: Could not delete temp backup file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,20 +310,34 @@ public class DatabaseManagementService implements ApplicationContextAware {
|
|||||||
|
|
||||||
System.err.println("PostgreSQL backup completed successfully");
|
System.err.println("PostgreSQL backup completed successfully");
|
||||||
|
|
||||||
// Read the backup file into memory
|
// Return the backup file as a streaming resource to avoid memory issues with large databases
|
||||||
byte[] backupData = Files.readAllBytes(tempBackupFile);
|
tempBackupFile.toFile().deleteOnExit();
|
||||||
return new ByteArrayResource(backupData);
|
return new org.springframework.core.io.FileSystemResource(tempBackupFile.toFile()) {
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
// Wrap the input stream to delete the temp file after it's fully read
|
||||||
|
return new java.io.FilterInputStream(super.getInputStream()) {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
super.close();
|
||||||
|
} finally {
|
||||||
|
// Clean up temp file after streaming is complete
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(tempBackupFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Log but don't fail - deleteOnExit will handle it
|
||||||
|
System.err.println("Warning: Could not delete temp backup file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new RuntimeException("Backup process was interrupted", e);
|
throw new RuntimeException("Backup process was interrupted", e);
|
||||||
} finally {
|
|
||||||
// Clean up temporary file
|
|
||||||
try {
|
|
||||||
Files.deleteIfExists(tempBackupFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Warning: Could not delete temporary backup file: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user