고민 포인트는 바로 환경이었다! 백업, 복구를 위해서는 dump 뜬 sql 파일을 저장할 경로가 필요했는데, 환경에 따라 경로가 달라야 했기 때문이다. 실제로 서비스가 배포된 환경은 우분투였으나, 로컬 개발 환경은 윈도우였고, 윈도우에 배포하고자 하는 상황이 추후 발생할 수도 있었기에, 양 운영체제에서 모두 동작하는 백업/복구 기능을 개발해야 했다
그래서 현재 os에 따라서 다른 경로를 가져오는 method를 DatabaseUtil에 생성하였다
현재 운영체제 조회
System.getProperty("os.name").toLowerCase().contains("win");
public String getFullBackupPath(String winBackupPath, String linuxBackupPath) {
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
if (isWindows) {
Path currentDir = Paths.get(System.getProperty("user.dir"));
if (currentDir.endsWith("backend"))
currentDir = currentDir.getParent();
return currentDir.toString() + winBackupPath;
} else {
return linuxBackupPath;
}
}
String[] winCmd = {
"cmd.exe", "/c",
"docker exec {containerName} pg_dump -U " + userName + " -d " + dbName + " -f " + "/tmp/"
+ backupFileName +
" && docker cp containerName}:" + "/tmp/" + backupFileName + " " + fullPath + backupFileName
};
String[] linuxCmd = {
"/bin/bash", "-c",
"sudo -u postgres pg_dump -U " + userName + " -d " + dbName + " -f " + fullPath + backupFileName
};
private final ExecutorService executor = Executors.newCachedThreadPool(); // 새로운 스레드풀 생성
@Scheduled(cron = "0 1 * * * 0") // Every Sunday at 1AM
public void backupDatabase() {
String backupFileName = "db_backup_" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".sql";
String dbName = databaseUtil.getDbName(dbUrl);
String fullPath = databaseUtil.getFullBackupPath(winBackupPath, linuxBackupPath);
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
String[] winCmd = {
"cmd.exe", "/c",
"docker exec madeg_postgres pg_dump -U " + userName + " -d " + dbName + " -f " + "/tmp/"
+ backupFileName +
" && docker cp madeg_postgres:" + "/tmp/" + backupFileName + " " + fullPath + backupFileName
};
String[] linuxCmd = {
"/bin/bash", "-c",
"sudo -u postgres pg_dump -U " + userName + " -d " + dbName + " -f " + fullPath + backupFileName
};
String[] cmd = isWindows ? winCmd : linuxCmd;
ProcessBuilder pb = new ProcessBuilder(cmd);
try {
Process process = pb.start();
boolean finished = process.waitFor(60, TimeUnit.SECONDS);
if (finished && process.exitValue() == 0) {
log.info("Database backup created successfully at " + fullPath + backupFileName);
} else {
log.error("Error occurred during database backup or timeout reached.");
}
} catch (InterruptedException | IOException e) {
log.error("Exception occurred during backup process", e);
} finally {
executor.shutdownNow();
}
}
@Scheduled(cron = "0 2 * * * 0") // Every Sunday at 2AM
public void deleteOldBackups() {
String fullPath = databaseUtil.getFullBackupPath(winBackupPath, linuxBackupPath);
LocalDate threeMonthAgo = LocalDate.now().minusMonths(3);
try (Stream<Path> files = Files.walk(Paths.get(fullPath))) {
files.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".sql"))
.forEach(path -> {
String fileName = path.getFileName().toString();
String datePart = fileName.replace("db_backup_", "").replace(".sql", "");
try {
LocalDate fileDate = LocalDate.parse(datePart, DateTimeFormatter.ofPattern("yyyyMMdd"));
if (fileDate.isBefore(threeMonthAgo)) {
File file = path.toFile();
if (file.delete()) {
log.info("Deleted old backup file: " + file.getPath());
} else {
log.error("Failed to delete file: " + file.getPath());
}
}
} catch (Exception e) {
log.error("Error deleting file: " + path, e);
}
});
} catch (IOException e) {
log.error("Error accessing backup directory: " + fullPath, e);
}
}
public void restoreDatabase(String backupFileName) {
String dbName = databaseUtil.getDbName(dbUrl);
String fullPath = databaseUtil.getFullBackupPath(winBackupPath, linuxBackupPath);
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
String[] winCmd = new String[] { "cmd.exe", "/c", "docker cp " + fullPath + backupFileName
+ " madeg_postgres:/tmp/" + backupFileName + " && " + "docker exec -i madeg_postgres psql -U "
+ userName + " -d " + dbName + " -f /tmp/"
+ backupFileName };
String[] linuxCmd = new String[] { "/bin/bash", "-c",
"sudo -u postgres psql -U " + userName + " -d " + dbName + " -f " + fullPath
+ backupFileName };
String[] cmd = isWindows ? winCmd : linuxCmd;
ProcessBuilder pb = new ProcessBuilder(cmd);
try {
Process process = pb.start();
boolean finish = process.waitFor(60, TimeUnit.SECONDS);
if (finish && process.exitValue() == 0) {
log.info("Database restored successfully from " + fullPath);
} else {
log.error("Error occurred during database restoration or timeout reached.");
}
} catch (InterruptedException | IOException e) {
log.error("Exception occurred during restore process", e);
}
}
백업 관련 공부하다가 블로그를 알게 되었습니다. 잘 보고 가요 :-)