headers
+ ) {
+ this.url = url;
+ this.connectTimeout = connectTimeout;
+ this.readTimeout = readTimeout;
+ this.proxyHost = proxyHost;
+ this.proxyPort = proxyPort;
+ this.useProxy = useProxy;
+ this.headers = headers != null ? headers : new HashMap<>();
+ }
+ }
+
+}
diff --git a/batch-quartz/src/main/java/com/spring/infra/feign/dto/TestRequest.java b/batch-quartz/src/main/java/com/spring/infra/feign/dto/TestRequest.java
new file mode 100644
index 0000000..99d6743
--- /dev/null
+++ b/batch-quartz/src/main/java/com/spring/infra/feign/dto/TestRequest.java
@@ -0,0 +1,9 @@
+package com.spring.infra.feign.dto;
+
+import lombok.Getter;
+
+@Getter
+public class TestRequest {
+ private String id;
+ private String name;
+}
diff --git a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java
index 0801a41..b4b2923 100644
--- a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java
+++ b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzConfig.java
@@ -94,7 +94,7 @@ public class QuartzConfig {
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setJobFactory(jobFactory);
- factory.setAutoStartup(false);
+ factory.setAutoStartup(true);
factory.setWaitForJobsToCompleteOnShutdown(true);
return factory;
}
diff --git a/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzShutdownListener.java b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzShutdownListener.java
new file mode 100644
index 0000000..21d8981
--- /dev/null
+++ b/batch-quartz/src/main/java/com/spring/infra/quartz/QuartzShutdownListener.java
@@ -0,0 +1,190 @@
+package com.spring.infra.quartz;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.PreDestroy;
+
+import org.quartz.JobExecutionContext;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerKey;
+import org.quartz.impl.matchers.GroupMatcher;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+* Quartz 스케줄러의 안전한 종료를 관리하는 리스너 클래스
+*
+* 이 클래스는 Spring 애플리케이션 컨텍스트가 종료될 때 Quartz 스케줄러의 모든 작업을
+* 안전하게 종료하고 정리하는 역할을 합니다. 실행 중인 작업이 정상적으로 완료될 때까지
+* 대기하며, 모든 트리거를 정리합니다.
+*
+* 주요 기능:
+*
+* - 실행 중인 작업의 안전한 종료 처리
+* - 트리거 상태 모니터링 및 정리
+* - 스케줄러 리소스의 정상적인 해제
+*
+*
+* @author [작성자 이름]
+* @version 1.0
+*/
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class QuartzShutdownListener implements ApplicationListener {
+
+ /** 작업 완료 대기 최대 시간 (밀리초) */
+ private static final long SHUTDOWN_WAIT_TIME = 30000L; // 30초
+
+ /** Quartz 스케줄러 인스턴스 */
+ private final Scheduler scheduler;
+
+
+ /**
+ * Spring 컨텍스트 종료 이벤트 발생 시 실행되는 메서드
+ *
+ * @param event 컨텍스트 종료 이벤트
+ */
+ @Override
+ public void onApplicationEvent(@NonNull ContextClosedEvent event) {
+ log.info("Quartz 셧다운 프로세스 시작...");
+ shutdownQuartzGracefully();
+ }
+
+ /**
+ * Quartz 스케줄러의 안전한 종료를 처리하는 메서드
+ *
+ * 다음의 단계를 순차적으로 실행합니다:
+ *
+ * - 새로운 작업 스케줄링 중지
+ * - 현재 실행 중인 작업 목록 확인
+ * - 실행 중인 작업의 상태 로깅
+ * - 작업 완료 대기
+ * - 트리거 정리
+ * - 스케줄러 종료
+ *
+ */
+ private void shutdownQuartzGracefully() {
+ try {
+ // 1. 새로운 작업 스케줄링 중지
+ scheduler.standby();
+ log.info("Scheduler를 대기 모드로 전환했습니다.");
+
+ // 2. 현재 실행 중인 작업 목록 확인
+ List currentJobs = scheduler.getCurrentlyExecutingJobs();
+ if (!currentJobs.isEmpty()) {
+ log.info("현재 실행 중인 작업 수: {}", currentJobs.size());
+
+ // 3. 실행 중인 작업의 정보 로깅
+ logRunningJobs(currentJobs);
+
+ // 4. 실행 중인 작업이 완료될 때까지 대기
+ waitForJobCompletion(currentJobs);
+ }
+
+ // 5. 모든 트리거 상태 확인 및 정리
+ cleanupTriggers();
+
+ // 6. 스케줄러 종료
+ performSchedulerShutdown();
+
+ } catch (SchedulerException e) {
+ log.error("Quartz 종료 중 오류 발생", e);
+ Thread.currentThread().interrupt();
+ } catch (InterruptedException e) {
+ log.error("Quartz 종료 대기 중 인터럽트 발생", e);
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * 실행 중인 작업들의 상세 정보를 로깅
+ *
+ * @param currentJobs 현재 실행 중인 작업 목록
+ */
+ private void logRunningJobs(List currentJobs) {
+ for (JobExecutionContext job : currentJobs) {
+ log.info("실행 중인 작업: {}, 트리거: {}, 시작 시간: {}",
+ job.getJobDetail().getKey(),
+ job.getTrigger().getKey(),
+ job.getFireTime()
+ );
+ }
+ }
+
+ /**
+ * 실행 중인 작업이 완료될 때까지 대기
+ *
+ * @param currentJobs 현재 실행 중인 작업 목록
+ * @throws InterruptedException 대기 중 인터럽트 발생 시
+ * @throws SchedulerException 스케줄러 관련 오류 발생 시
+ */
+ private void waitForJobCompletion(List currentJobs)
+ throws InterruptedException, SchedulerException {
+ long startTime = System.currentTimeMillis();
+ while (!currentJobs.isEmpty() &&
+ (System.currentTimeMillis() - startTime) < SHUTDOWN_WAIT_TIME) {
+ log.info("실행 중인 작업이 완료될 때까지 대기 중...");
+ Thread.sleep(1000);
+ currentJobs = scheduler.getCurrentlyExecutingJobs();
+ }
+ }
+
+ /**
+ * 모든 트리거를 정리
+ *
+ * @throws SchedulerException 스케줄러 관련 오류 발생 시
+ */
+ private void cleanupTriggers() throws SchedulerException {
+ List groups = scheduler.getTriggerGroupNames();
+ for (String group : groups) {
+ Set triggerKeys = scheduler.getTriggerKeys(GroupMatcher.groupEquals(group));
+ for (TriggerKey triggerKey : triggerKeys) {
+ try {
+ Trigger trigger = scheduler.getTrigger(triggerKey);
+ if (trigger != null) {
+ scheduler.unscheduleJob(triggerKey);
+ log.info("트리거 제거됨: {}", triggerKey);
+ }
+ } catch (Exception e) {
+ log.error("트리거 제거 중 오류 발생: {}", triggerKey, e);
+ }
+ }
+ }
+ }
+
+ /**
+ * 스케줄러 종료 수행
+ *
+ * @throws SchedulerException 스케줄러 관련 오류 발생 시
+ */
+ private void performSchedulerShutdown() throws SchedulerException {
+ scheduler.clear();
+ scheduler.shutdown(true); // true = 실행 중인 작업이 완료될 때까지 대기
+ log.info("Quartz 스케줄러가 정상적으로 종료되었습니다.");
+ }
+
+ /**
+ * 애플리케이션 컨텍스트 종료 전 실행되는 정리 메서드
+ */
+ @PreDestroy
+ public void preDestroy() {
+ try {
+ if (!scheduler.isShutdown()) {
+ log.info("ApplicationContext 종료 전 Quartz 정리 작업 수행");
+ shutdownQuartzGracefully();
+ }
+ } catch (SchedulerException e) {
+ log.error("PreDestroy 단계에서 Quartz 종료 중 오류 발생", e);
+ }
+ }
+
+}
diff --git a/batch-quartz/src/main/resources/application.yml b/batch-quartz/src/main/resources/application.yml
index 1fca658..1a65d51 100644
--- a/batch-quartz/src/main/resources/application.yml
+++ b/batch-quartz/src/main/resources/application.yml
@@ -102,7 +102,7 @@ batch-info:
email-send-batch:
group: "EMAIL"
job-name: "emailSendJob"
- cron-expression: "*/20 * * * * ?"
+ cron-expression: "*/10 * * * * ?"
description: "이메일배치작업"
post-batch:
group: "POST"
@@ -113,7 +113,36 @@ batch-info:
group: "POST"
job-name: "postCreateJob"
cron-expression: "0/30 * * * * ?"
- description: "테스트배치작업"
+ description: "테스트배치작업"
+
+feign:
+ okhttp:
+ enabled: true
+ client:
+ config:
+ default:
+ connectTimeout: 5000
+ readTimeout: 5000
+ loggerLevel: full
+ compression:
+ request:
+ enabled: true
+ response:
+ enabled: true
+
+ clients:
+ client1:
+ url: http://localhost:8082
+ connectTimeout: 5000
+ readTimeout: 5000
+ useProxy: true
+ proxyHost: http://localhost:8083
+ proxyPort: 8083
+ client2:
+ url: http://api1.example.com
+ headers:
+ Client1-Specific-Header: Value1
+ Another-Client1-Header: AnotherValue1
jwt:
access-token:
@@ -123,6 +152,14 @@ jwt:
secret: bnhjdXMyLjAtcGxhdGZvcm0tcHJvamVjdC13aXRoLXNwcmluZy1ib290bnhjdF9zdHJvbmdfY29tcGxleF9zdHJvbmc=
expiration: 10080
+path:
+ paths:
+ path1:
+ upload: /path1/upload
+ path2:
+ upload: /path2/upload
+ dowonload: /path2/dowonload
+
management:
endpoints:
web: