feat : war cd
parent
ca2e042a96
commit
16553744c9
@ -1,4 +1,4 @@
|
||||
package com.worker.scheduler.smg.sechdule;
|
||||
package com.worker.scheduler.smg.schedule;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@ -0,0 +1,155 @@
|
||||
package com.worker.scheduler.update.schedule;
|
||||
|
||||
import com.jcraft.jsch.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.Properties;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WarSyncScheduler {
|
||||
|
||||
// OS 확인
|
||||
private final String os = System.getProperty("os.name").toLowerCase();
|
||||
private final boolean isWindows = os.contains("win");
|
||||
|
||||
// SFTP 설정
|
||||
private final String SFTP_HOST = "211.119.124.103";
|
||||
private final int SFTP_PORT = 1922;
|
||||
private final String SFTP_USER = "cc-war";
|
||||
private final String SFTP_PASS = "xit5811807!";
|
||||
// private final String REMOTE_CC_WAR_PATH = "D:\\prod-cc\\deploy\\clean-parking-boot.war";
|
||||
private final String REMOTE_CC_WAR_PATH = "/deploy/clean-parking-boot.war";
|
||||
|
||||
|
||||
// 경로 설정
|
||||
private final Path LOCAL_WAR_PATH = isWindows
|
||||
? Paths.get("D://prod-cc/deploy/clean-parking-boot.war")
|
||||
: Paths.get("/opt/prod-cc/deploy/clean-parking-boot.war");
|
||||
|
||||
private final Path LOCAL_TMP_PATH = isWindows
|
||||
? Paths.get("D://prod-cc/tmp/clean-parking-boot.war")
|
||||
: Paths.get("/opt/prod-cc/tmp/clean-parking-boot.war");
|
||||
|
||||
private final Path LoCAL_BACKUP_PATH = isWindows
|
||||
? Paths.get("D://prod-cc/backup/clean-parking-boot.war")
|
||||
: Paths.get("/opt/prod-cc/backup/clean-parking-boot.war");
|
||||
|
||||
private final Path META_FILE_PATH = isWindows
|
||||
? Paths.get("D://prod-cc/meta/clean-parking.war.meta")
|
||||
: Paths.get("/opt/prod-cc/meta/clean-parking.war.meta");
|
||||
|
||||
private final Path PID_FILE_PATH = isWindows
|
||||
? Paths.get("D://prod-cc/deploy/clean-parking.pid")
|
||||
: Paths.get("/opt/prod-cc/deploy/clean-parking.pid");
|
||||
|
||||
private final File LOG_FILE = isWindows
|
||||
? new File("D://prod-cc/logs/clean-parking.log")
|
||||
: new File("/opt/prod-cc/logs/clean-parking.log");
|
||||
|
||||
@Scheduled(fixedRate = 5 * 60 * 1000) // 5분
|
||||
// @Scheduled(cron = "0 0 2 * * *") // 매일 새벽 2시
|
||||
public void checkAndDeploy() {
|
||||
log.info("[배포] SFTP에서 .war 변경 여부 확인 시작");
|
||||
|
||||
Session session = null;
|
||||
ChannelSftp sftp = null;
|
||||
|
||||
try {
|
||||
// SFTP 연결
|
||||
JSch jsch = new JSch();
|
||||
session = jsch.getSession(SFTP_USER, SFTP_HOST, SFTP_PORT);
|
||||
session.setPassword(SFTP_PASS);
|
||||
Properties config = new Properties();
|
||||
config.put("StrictHostKeyChecking", "no");
|
||||
session.setConfig(config);
|
||||
session.connect();
|
||||
|
||||
sftp = (ChannelSftp) session.openChannel("sftp");
|
||||
sftp.connect();
|
||||
|
||||
// 리모트 파일 속성
|
||||
SftpATTRS attrs = sftp.lstat(REMOTE_CC_WAR_PATH);
|
||||
long remoteSize = attrs.getSize();
|
||||
int remoteMtime = attrs.getMTime();
|
||||
|
||||
// 메타파일 비교
|
||||
boolean isUpdated = isWarUpdated(remoteSize, remoteMtime);
|
||||
|
||||
if (!isUpdated) {
|
||||
log.info("[배포] 변경 없음. 스킵");
|
||||
return;
|
||||
}
|
||||
|
||||
// 다운로드
|
||||
try (InputStream in = sftp.get(REMOTE_CC_WAR_PATH)) {
|
||||
Files.copy(in, LOCAL_TMP_PATH, StandardCopyOption.REPLACE_EXISTING);
|
||||
log.info("[배포] SFTP 다운로드 완료");
|
||||
}
|
||||
|
||||
// 실행 중이면 종료
|
||||
killPreviousWar();
|
||||
|
||||
// 교체
|
||||
Files.move(LOCAL_TMP_PATH, LOCAL_WAR_PATH, StandardCopyOption.REPLACE_EXISTING);
|
||||
log.info("[배포] WAR 파일 교체 완료");
|
||||
|
||||
// 실행
|
||||
runWar();
|
||||
log.info("[배포] WAR 실행 완료");
|
||||
|
||||
// 메타 저장
|
||||
String meta = remoteSize + "," + remoteMtime;
|
||||
Files.writeString(META_FILE_PATH, meta);
|
||||
log.info("[배포] 메타 저장 완료");
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[배포] 실패", e);
|
||||
} finally {
|
||||
if (sftp != null) sftp.disconnect();
|
||||
if (session != null) session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWarUpdated(long remoteSize, int remoteMtime) throws IOException {
|
||||
if (!Files.exists(META_FILE_PATH)) return true;
|
||||
|
||||
String[] parts = Files.readString(META_FILE_PATH).trim().split(",");
|
||||
long prevSize = Long.parseLong(parts[0]);
|
||||
int prevMtime = Integer.parseInt(parts[1]);
|
||||
|
||||
return (remoteSize != prevSize || remoteMtime != prevMtime);
|
||||
}
|
||||
|
||||
private void killPreviousWar() {
|
||||
try {
|
||||
if (!Files.exists(PID_FILE_PATH)) return;
|
||||
|
||||
long pid = Long.parseLong(Files.readString(PID_FILE_PATH).trim());
|
||||
|
||||
String[] cmd = isWindows
|
||||
? new String[]{"taskkill", "/F", "/PID", String.valueOf(pid)}
|
||||
: new String[]{"kill", "-9", String.valueOf(pid)};
|
||||
|
||||
new ProcessBuilder(cmd).start();
|
||||
log.info("[배포] 기존 프로세스 종료 완료");
|
||||
} catch (Exception e) {
|
||||
log.warn("[배포] 기존 종료 실패: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void runWar() throws IOException {
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "-jar", LOCAL_WAR_PATH.toString());
|
||||
pb.directory(LOCAL_WAR_PATH.getParent().toFile());
|
||||
pb.redirectOutput(LOG_FILE);
|
||||
pb.redirectErrorStream(true);
|
||||
Process process = pb.start();
|
||||
|
||||
Files.writeString(PID_FILE_PATH, String.valueOf(process.pid()));
|
||||
log.info("[배포] 새 PID 저장: " + process.pid());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue