인프런 커뮤니티 질문&답변
2장. 작전2: 분산 서버 로그 처형 작전 (시스템에 의존적인) SystemCommandTasklet 관련 질문
작성
·
41
·
수정됨
1
안녕하십니까 형님!
2강 작전2 : 분산 서버 로그 처형 작전 관련해서, 실무적으로 어떠한 방향으로 접근하는 것이 좋을지 의문이 생겨서 질문 드려봅니다!
제가 윈도우 환경에서 실행하다보니, 자료에 기술된 cli를 윈도우 환경으로 바꾸는데 많은 비용을 소모하였습다.
특히 이번 내용의 경우,
단순 개행문자 및 OS간 인식문제를 넘어서, 명령어를 아예 윈도우 환경에 맞게 변경을 해야한다는 점에서 다소 힘이 많이 들었던 것 같습니다.
뿐만 아니라, 윈도우 cmd 환경에서의 실행을 고려해서 cmd -c의 명령어를 추가해준다든지, 리눅스의 mkdir -p가 먹히지 않으므로 mkdir를 &&로 이어서 실행하게끔 한다든지..(이러다보니 collected_logs 폴더도 최초부터 존재하지 않아야 정상 실행이 가능한 환경적 제약사항까지 고려해야 하였습니다)
전체적으로 환경의 차이를 많이 느끼고 그만큼의 비용도 일전보다는 훨씬 많이 소모된 느낌이 있었던 내용이었습니다.
//-p 옵션은 윈도우에서 안먹힘..따라서 collected_logs라는 디렉토리 생성(mkdir)은 처음부터 존재하지 않아야 한다.
//SystemCommandTasklet -> 반드시 cli 명령어 작성 필요
@Bean
@StepScope
public SystemCommadTasklet mkdirTasklet(
@Value("#{jobParameters['date']}") String date) throws IOException {
SystemCommandTasklet tasklet = new SystemCommandTasklet();
// //tasklet.setWorkingDirectory(System.getProperty("user.home"));
//실행환경은 batch 명령어 작성환경에 상관없이 무조건 cmd
//경로직접주임은 반드시 백슬래쉬
tasklet.setWorkingDirectory("C:\\Users\\gyrbs\\OneDrive\\Desktop");
String collectedLogsPath = "collected_logs\\" + date;
String processedLogsPath = "processed_logs\\" + date;
//String collectedLogsPath = String.format("collected_logs\\%s", date);
//String processedLogsPath = String.format("processed_logs\\%s", date);
String command = String.format("mkdir %s && mkdir %s", collectedLogsPath, processedLogsPath);
//
//tasklet.setCommand("mkdir", "-p", collectedLogsPath, processedLogsPath);
//tasklet.setCommand("cmd", "/c", "mkdir", collectedLogsPath);
tasklet.setCommand("cmd", "/c", command);
tasklet.setTimeout(3000); // 3초 타임아웃
return tasklet;
}@Bean
@StepScope
public SystemCommandTasklet scpTasklet(
@Value("#{jobParameters['date']}") String date) {
SystemCommandTasklet tasklet = new SystemCommandTasklet();
//tasklet.setWorkingDirectory(System.getProperty("user.home"));
String rootDirectory = "C:\\Users\\gyrbs\\OneDrive\\Desktop";
tasklet.setWorkingDirectory(rootDirectory);
String collectedLogsPath = String.format("collected_logs\\%s", date);
StringJoiner commandBuilder = new StringJoiner(" && ");
for (String host : List.of("localhost", "loan", "pay")) {
//String command = String.format("scp %s:~\\logs\\%s.log .%s\\%s.log",
// host, date, processedLogsPath, host);
String src = String.format("logs\\%s.log", date);
String dest = String.format("%s\\%s.log", collectedLogsPath, host);
commandBuilder.add(String.format("copy %s %s", src, dest));
}
//String src = String.format("logs\\%s.log", date);
//String dest = String.format("%s\\%s.log", collectedLogsPath, "localhost");
tasklet.setCommand("cmd", "/c", commandBuilder.toString());
tasklet.setTimeout(10000); //10초 타임아웃
return tasklet;
}
이런 느낀점이 많다보니, 이번 내용을 진행하면서, SystemCommandTasklet을 실무적으로 어떻게 활용하면 좋을지 의문점이 생겼습니다.
첫번째는, 단순히 배치를 실행하는 환경이 리눅스라면, 리눅스 환경은 어차피 한동안 안고쳐질거니까, 윈도우라면 그것대로 윈도우 배치 환경은 거의 변경이 없겠지?라는 생각으로 단순히 SystemCommandTasklet으로 구성해야겠네!라고 생각하는게 맞는지 일단 의문이 들었습니다.
배치라는게 이러한 환경적 독립성을 유지하지 않고, 배치실행환경에 맞게 일단 구성하는게 맞을까요?
물론 이 내용이 SystemCommandTasklet을 배우는데 중점이 있을 수 있겠지만, 이번에 꽤 많은 소모를 느껴서 질문드리게 되었습니다!
두번째로, SystemCommandTasklet이 아닌 Tasklet을 사용하여 아래와 같이 시스템에 의존하지 않고 모든 시스템에 적용이 가능한 Java API버전으로 구성하였는데, 빌드 성공하긴 했습니다.
//-p 옵션은 윈도우에서 안먹힘..따라서 collected_logs라는 디렉토리 생성(mkdir)은 처음부터 존재하지 않아야 한다.
//tasklet -> return (con, ch)
@Bean
@StepScope
public Tasklet mkdirTasklet(
@Value("#{jobParameters['date']}") String date) throws IOException {
return ((contribution, chunkContext) -> {
Path desktop = Paths.get("C:\\Users\\gyrbs\\OneDrive\\Desktop");
Path collected = desktop.resolve("collected_logs").resolve(date);
Path processed = desktop.resolve("processed_logs").resolve(date);
Files.createDirectories(collected);
Files.createDirectories(processed);
return RepeatStatus.FINISHED;
});
}
이렇게 처음부터 시스템에 상관없는(상관없이 구동이 가능한) 로직을 구현하는게 유지보수적으로도 맞지 않을까..하는 생각이 들었습니다. 형님께서는 실무적으로 이를 적용할때 어떠한 방향으로 구성하시는지, 제가 지금 의문이 드는게 맞는것인지.. 궁금해서 질문드려봅니다!(아니면 만약 SystemCommandTasklet과 같이 시스템에 의존적인 구현이 필요하다면, 이 경우는 환경적으로 바뀔 가능성이 현저히 적다던가..이러한 특수적인 상황적 조건이 있을때 사용하실까요?)
제약사항이 생각보다 커져서 배꼽이 더 커지는 상황이었기에, 형님께 여쭤보고자 하였습니다!
감사합니다!
답변 2
0
0
안녕하세요, 인프런 AI 인턴입니다.
Hyo Kyun Lee님께서 제기하신 SystemCommandTasklet와 시스템 독립성 관련 고민에 대한 의견을 드리겠습니다.
SystemCommandTasklet 사용에 대한 고민
환경에 따라 명령어가 다르게 처리되어야 하는 상황에서는 SystemCommandTasklet를 환경별로 따로 구성하는 것이 일반적입니다. 리눅스와 윈도우 환경 각각에 맞게 스크립트를 제공하고, Spring Profile을 사용하여 환경 설정을 분리할 수 있습니다. 이를 통해 유지보수를 체계적으로 할 수 있으며, 각 환경에 최적화된 명령어를 사용할 수 있습니다.Java 기반의 시스템 독립적인 Tasklet 구성
시스템 종속성을 줄이기 위해 Java API를 활용하여 작업을 수행하는 것은 매우 좋은 접근입니다. OS에 의존하지 않는 Java API를 이용한 디렉토리 생성 등은 특히 운영체제가 혼합되어 있을 가능성이 높은 환경에서 유용하며, 코드의 유지보수성이 높아집니다. 이러한 방식은 배포해야 할 코드량도 줄일 수 있어 보다 효율적일 수 있습니다.실무 적용 시 고려사항
시스템에 의존적인 구현이 필요할 경우, 해당 코드가 실행되는 환경적으로 큰 변동이 없거나, 필요에 따라 환경별 최적화가 중요한 경우에만 의존적인 방법을 사용합니다. 예를 들어, 성능 때문에 특정 시스템의 명령어를 꼭 사용해야 하는 경우가 이에 해당됩니다.
Hyo Kyun Lee님께서 고민하시는 방향은 매우 적절하며, 실무에서는 보다 유연하고 유지보수 용이한 코드 작성을 지향하는 것이 중요합니다. 특정 운영체제에 강하게 의존할 필요가 없는 경우 가급적 시스템 독립적으로 구현하는 것이 좋습니다.
추가로, Spring Batch의 다양한 기능과 API를 충분히 활용하면 더 많은 문제를 해결할 수 있으니 관련 문서와 커뮤니티 자료도 참고하시면 좋을 것입니다.
Spring Batch 관련 문서
더 궁금한 점이 있으면 언제든지 질문해 주세요. 감사합니다!




