이 2가지 조건을 만족하게 열심히 검색하고 쿼리를 만들어봤어요. 찾아보니 "5일 연속 지각" 이런 게시글이 많이 보여서 참고를 했어요.
01011112222
발송완료
2024/02/06 18:01:01
01011112222
인증완료
2024/02/06 18:00:01
01011112222
발송완료
2024/02/06 17:59:01
01011112222
발송완료
2024/02/06 17:58:01
01011112222
발송완료
2024/02/06 17:57:01
01011112222
발송완료
2024/02/06 17:56:01
샘플 데이터가 있어요
발송완료
2024/02/06 18:01:01
인증완료
2024/02/06 18:00:01
발송완료
2024/02/06 17:59:01
발송완료
2024/02/06 17:58:01
발송완료
2024/02/06 17:57:01
발송완료
2024/02/06 17:56:01
5번째에 인증을 완료했으므로 발송 횟수를 초기화
발송완료
2024/02/06 18:01:01
N
인증완료
2024/02/06 18:00:01
Y
발송완료
2024/02/06 17:59:01
N
발송완료
2024/02/06 17:58:01
N
발송완료
2024/02/06 17:57:01
N
발송완료
2024/02/06 17:56:01
N
6번째에는 발송이되야 하고
발송완료
2024/02/06 18:01:01
N
발송완료
2024/02/06 18:00:01
N
발송완료
2024/02/06 17:59:01
N
발송완료
2024/02/06 17:58:01
N
발송완료
2024/02/06 17:57:01
N
발송완료
2024/02/06 17:56:01
N
6번째에 발송이 안되어야 해요.
그럼 어떻게 이걸 체크를 했는지 쿼리를 작성해 볼게요.
SELECT
CASE WHEN LISTAGG(YN) WITHIN GROUP (ORDER BY 등록시간) LIKE '%YYYYY%' THEN 'Y' ELSE 'N' END
FROM (
SELECT 핸드폰번호,결과,등록시간
DECODE(결과,'발송완료','Y','N') AS YN
FROM TABLE
WHERE 등록시간 > SYSDATE - 1 / 24 --지금부터 1시간이내
AND 핸드폰번호 = '01011112222'
ORDER BY 등록시간 DESC
)
해당방법으로 Y가 연속으로 몇 개 있냐 이걸로 5번 발송요청 4번 발송요청 이렇게 조절을 할 수 있어요.
해당쿼리로
- 1시간 안에 본인증 문자 발송이 5회 이상 안되도록
- 본인증이 완료가 되면 5회 카운터 초기화
두 가지 조건을 만족하여 개발을 했습니다. 처음에 요건을 들었을 때 JAVA에서 풀어야 하나 고민을 했지만 역시 검색으로 힌트를 얻어 쿼리로 해결을 했어요.
월래는 Batch를 이용하여 새벽시간에 동작을 하도록 적용을 하였는데 @Async를 이용하여 빠르게 선처리 작업을 하고 이후 Async메서드를 호출하여 비동기 방식으로 작동하도록 구현을 하였습니다.
@Configuration
@EnableScheduling
@EnableAsync
public class AsyncThreadConfiguration {
@Bean(name = "asyncExecutor")
public Executor asyncThreadTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(2); //최초생성수
threadPoolTaskExecutor.setMaxPoolSize(4); //max생성수
threadPoolTaskExecutor.setThreadNamePrefix("fabs-batch-pool");
return threadPoolTaskExecutor;
}
public class HandlingExecutor implements AsyncTaskExecutor {
private final AsyncTaskExecutor executor;
public HandlingExecutor(AsyncTaskExecutor executor) {
this.executor = executor;
}
@Override
public void execute(Runnable task) {
executor.execute(createWrappedRunnable(task));
}
@Override
public void execute(Runnable task, long startTimeout) {
executor.execute(createWrappedRunnable(task), startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
return executor.submit(createWrappedRunnable(task));
}
@Override
public <T> Future<T> submit(final Callable<T> task) {
return executor.submit(createCallable(task));
}
private <T> Callable<T> createCallable(final Callable<T> task) {
return () -> {
try {
return task.call();
} catch (Exception ex) {
handle(ex);
throw ex;
}
};
}
private Runnable createWrappedRunnable(final Runnable task) {
return () -> {
try {
task.run();
} catch (Exception ex) {
handle(ex);
}
};
}
private void handle(Exception ex) {
log.info("Failed to execute task. : {}", ex.getMessage());
log.error("Failed to execute task. ", ex);
}
public void destroy() {
if (executor instanceof ThreadPoolTaskExecutor) {
((ThreadPoolTaskExecutor) executor).shutdown();
}
}
}
먼저 ThreadPool설정입니다.
setCorePoolSize 최초 생성 시 사용되는 Thread 수입니다.
setMaxPoolSize 생성할 수 있는 Thread Max값입니다.
setThreadNamePrefix ThreadPool이 여러 곳에서 사용이 되면 알아볼 수 있도록 Name을 지정합니다.
@Bean(name = "asyncExecutor") <- "asyncExecutor"이름으로 비동기 호출을 사용할 수 있습니다.
//Controller Class
@RequestMapping(value = "/excelUpload", method = RequestMethod.POST)
public ResponseEntity<HttpResponse<?>> excelUpload(MultipartHttpServletRequest req, HttpServletResponse res,
@AuthenticationPrincipal UserAuthentication userAuthentication) throws Exception {
//비동기 Method호출
Service.add(reqFundManagement);
//비동기 Method 실행이 다 완료 안되더라도 이후 코드 실행
}
//Service Class
@Async("asyncExecutor")
public void add(ReqFundManagement reqFundManagement) {
// 필요한 소스구현
}
기존 방식은
1) Excel업로드
2) 대상자 추출(LIST)
3) 대상자 등록
4) 대상자 API를 이용해 데이터 가져오기
대상자가 많을수록 3->4번이 대기 시간들이 길어져서 Batch로 만들려고 고민 중에 비동기 호출 방식 확인
비동기
1) Excel업로드
2) 대상자 추출(LIST)
3) 대상자 등록
4) 대상자 API를 이용해 데이터 가져오기
호출 순서는 같은데 3->4번 실행 후 4번 응답 대기 없이 바로 3->4가 반복을 하여 3번 대상자 먼저 등록이 되고 4번은 비동기로 작동이 돼서 여러 건을 동시에 가져와서 호출 시간이 절약이 되었어요.
Jquery Datepicker를 동적으로 생성을 하면 동작을 안 하는데 동적 생성법을 포스팅해볼게요.
$(document).ready(function(){
function 동적생성(){
//페이지에 적용된 class를 삭제
$(".ui-datepicker-trigger").remove();
//필요한 Datepicker에 다시 적용
$("input[name='researchStartDtm'],input[name='researchEndDtm']").removeClass('hasDatepicker').datepicker();
}
});
위 코드처럼 기존 class를 삭제를 하고 다시 적용을 시켜주면 정상 작동을 할 수 있습니다.