From 4fbf130326532505541103e07427edcf2e620407 Mon Sep 17 00:00:00 2001 From: htlee Date: Mon, 2 Mar 2026 16:44:06 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(websocket):=20cancelQuery=20idempotent?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=E2=80=94=20=EC=99=84=EB=A3=8C=EB=90=9C?= =?UTF-8?q?=20=EC=BF=BC=EB=A6=AC=20=EC=B7=A8=EC=86=8C=20=EC=8B=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EB=8C=80=EC=8B=A0=20=EC=A0=95=EC=83=81=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - parseTimestamp 실패 로깅 추가 (AreaSearchService) - isNightTimeContact 야간 판정 로직 단순화 (VesselContactService) Co-Authored-By: Claude Opus 4.6 --- .../domain/gis/service/AreaSearchService.java | 1 + .../gis/service/VesselContactService.java | 31 +++++-------------- .../controller/StompTrackController.java | 5 ++- 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/main/java/gc/mda/signal_batch/domain/gis/service/AreaSearchService.java b/src/main/java/gc/mda/signal_batch/domain/gis/service/AreaSearchService.java index b434963..02acce9 100644 --- a/src/main/java/gc/mda/signal_batch/domain/gis/service/AreaSearchService.java +++ b/src/main/java/gc/mda/signal_batch/domain/gis/service/AreaSearchService.java @@ -438,6 +438,7 @@ public class AreaSearchService { try { return Long.parseLong(timestamps.get(index)); } catch (NumberFormatException e) { + log.warn("Invalid timestamp at index {}: {}", index, timestamps.get(index)); return 0L; } } diff --git a/src/main/java/gc/mda/signal_batch/domain/gis/service/VesselContactService.java b/src/main/java/gc/mda/signal_batch/domain/gis/service/VesselContactService.java index 047aa6c..8b0f357 100644 --- a/src/main/java/gc/mda/signal_batch/domain/gis/service/VesselContactService.java +++ b/src/main/java/gc/mda/signal_batch/domain/gis/service/VesselContactService.java @@ -360,27 +360,15 @@ public class VesselContactService { * 접촉 구간이 22:00~06:00 KST에 포함되는지 판단. */ private boolean isNightTimeContact(long contactStartSec, long contactEndSec) { - Instant startInstant = Instant.ofEpochSecond(contactStartSec); - Instant endInstant = Instant.ofEpochSecond(contactEndSec); + ZonedDateTime startKst = Instant.ofEpochSecond(contactStartSec).atZone(KST); + ZonedDateTime endKst = Instant.ofEpochSecond(contactEndSec).atZone(KST); - ZonedDateTime startKst = startInstant.atZone(KST); - ZonedDateTime endKst = endInstant.atZone(KST); - - // 접촉 구간 내 모든 날짜에 대해 야간 시간대 겹침 체크 + // 각 날짜의 야간 구간(22:00~익일 06:00)과 접촉 구간 겹침 체크 LocalDate day = startKst.toLocalDate(); - LocalDate lastDay = endKst.toLocalDate().plusDays(1); - - while (!day.isAfter(lastDay)) { - // 해당 날짜의 야간: 전날 22:00 ~ 당일 06:00 - ZonedDateTime nightStart = day.atTime(LocalTime.of(22, 0)).atZone(KST).minusDays(1); - ZonedDateTime nightEnd = day.atTime(LocalTime.of(6, 0)).atZone(KST); - - // 당일 22:00 ~ 다음날 06:00 - ZonedDateTime nightStart2 = day.atTime(LocalTime.of(22, 0)).atZone(KST); - ZonedDateTime nightEnd2 = day.plusDays(1).atTime(LocalTime.of(6, 0)).atZone(KST); - - if (isOverlapping(startKst, endKst, nightStart, nightEnd) - || isOverlapping(startKst, endKst, nightStart2, nightEnd2)) { + while (!day.isAfter(endKst.toLocalDate())) { + ZonedDateTime nightStart = day.atTime(22, 0).atZone(KST); + ZonedDateTime nightEnd = day.plusDays(1).atTime(6, 0).atZone(KST); + if (startKst.isBefore(nightEnd) && endKst.isAfter(nightStart)) { return true; } day = day.plusDays(1); @@ -388,11 +376,6 @@ public class VesselContactService { return false; } - private boolean isOverlapping(ZonedDateTime s1, ZonedDateTime e1, - ZonedDateTime s2, ZonedDateTime e2) { - return s1.isBefore(e2) && s2.isBefore(e1); - } - // ── 추정 속도 계산 ── /** diff --git a/src/main/java/gc/mda/signal_batch/global/websocket/controller/StompTrackController.java b/src/main/java/gc/mda/signal_batch/global/websocket/controller/StompTrackController.java index 05ccc55..1b75ad8 100644 --- a/src/main/java/gc/mda/signal_batch/global/websocket/controller/StompTrackController.java +++ b/src/main/java/gc/mda/signal_batch/global/websocket/controller/StompTrackController.java @@ -113,10 +113,9 @@ public class StompTrackController { trackStreamingService.cancelQuery(queryId); chunkedTrackStreamingService.cancelQuery(queryId); activeSessions.remove(sessionId); - return QueryResponse.cancelled(queryId); } - - return QueryResponse.error(queryId, "Query not found"); + // 세션 없어도 취소 성공 반환 (idempotent — 이미 완료/취소된 쿼리) + return QueryResponse.cancelled(queryId); } /** -- 2.45.2 From bfed21dcb4f4612fa989cce9482f5292cd06d829 Mon Sep 17 00:00:00 2001 From: htlee Date: Mon, 2 Mar 2026 16:44:46 +0900 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20?= =?UTF-8?q?=EB=85=B8=ED=8A=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/RELEASE-NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index 386935b..535dc8e 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -4,6 +4,10 @@ ## [Unreleased] +### 수정 +- cancelQuery idempotent 처리 — 완료된 쿼리 취소 시 에러 대신 정상 응답 +- parseTimestamp 실패 로깅 추가, isNightTimeContact 야간 판정 로직 단순화 + ## [2026-03-02.2] ### 변경 -- 2.45.2