diff --git a/WebContent/jsp/onl/apim/webhook/webhookSendLogMan.jsp b/WebContent/jsp/onl/apim/webhook/webhookSendLogMan.jsp index 1007a35..0c88f88 100644 --- a/WebContent/jsp/onl/apim/webhook/webhookSendLogMan.jsp +++ b/WebContent/jsp/onl/apim/webhook/webhookSendLogMan.jsp @@ -89,7 +89,7 @@ mtype: 'POST', url: url, postData: getSearchForJqgrid("cmd", "LIST"), - colNames: ['id', 'No.', '기관명', '이벤트유형', 'Target URL', 'Proxy URL', 'Status', '성공여부', '발송서버', '발송일시'], + colNames: ['id', 'No.', '기관명', '이벤트유형', 'Target URL', 'Proxy URL', 'Status', '성공여부', '재시도', '발송서버', '발송일시'], colModel: [ {name: 'id', align: 'center', key: true, hidden: true}, {name: 'rowNum', align: 'center', width: 45, sortable: false}, @@ -99,11 +99,12 @@ {name: 'proxyUrl', align: 'left', width: 300, formatter: formatTargetUrl}, {name: 'statusCode', align: 'center', width: 60}, {name: 'success', align: 'center', width: 70, formatter: formatSuccess}, + {name: 'retryCount', align: 'center', width: 60}, {name: 'sendBy', align: 'center', width: 100}, {name: 'sentAt', align: 'center', width: 140} ], jsonReader: {repeatitems: false}, - pager: $('#pager'), + pager: $('#pager'), page: '${param.page}', rowNum: '${rmsDefaultRowNum}', autoheight: true, diff --git a/src/main/java/com/eactive/eai/rms/ext/djb/webhook/service/WebhookService.java b/src/main/java/com/eactive/eai/rms/ext/djb/webhook/service/WebhookService.java index c0bfdae..35b54b4 100644 --- a/src/main/java/com/eactive/eai/rms/ext/djb/webhook/service/WebhookService.java +++ b/src/main/java/com/eactive/eai/rms/ext/djb/webhook/service/WebhookService.java @@ -17,7 +17,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; @@ -146,8 +145,12 @@ public class WebhookService { /** * 웹훅 발송 메인 메서드 + * + *
{@code @Transactional}을 두지 않는다 - 재시도(최대 retryCount회, Thread.sleep 포함)가 + * 이 메서드 안에서 동기로 도는데, 메서드 전체를 하나의 트랜잭션으로 감싸면 재시도 도중의 + * 실패 로그 저장(sendWithRetry 내부)이 커밋되지 않고 메서드가 끝날 때까지 대기하게 되어 + * "실패 시 즉시 로그부터 남긴다"는 의도가 무의미해진다. save() 호출마다 개별 커밋되도록 둔다.
*/ - @Transactional public void send(WebhookSendRequest req) { String targetUrl = req.getTargetUrl(); @@ -235,6 +238,8 @@ public class WebhookService { * 재시도 포함 HTTP 발송 * - 4xx: 클라이언트 오류이므로 즉시 throw (재시도 불필요) * - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 선형 증가 backoff 재시도 (1s → 2s → 3s → 4s → 5s) + * - 실패할 때마다 즉시 로그를 저장한다 (최초 실패는 INSERT, 이후 재시도 실패는 같은 row를 UPDATE) - + * 재시도 도중 앱이 죽어도 마지막으로 저장된 실패 기록이 남도록 하기 위함 */ private ResponseEntity