From 17c646e87a861119710f9b67995b52ab01727834 Mon Sep 17 00:00:00 2001 From: htlee Date: Thu, 19 Feb 2026 22:51:55 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20V2=20=EC=BA=90=EC=8B=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=8B=9C=20=EB=88=84=EB=9D=BD=20MMSI=20DB=20fallba?= =?UTF-8?q?ck=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L1/L2 캐시에 다른 선박 데이터가 있어 HIT로 판정되지만 요청한 MMSI가 캐시에 없을 때 DB fallback이 누락되는 버그 수정. filterByMmsi() 후 누락된 MMSI에 대해 부분 DB fallback 실행. Co-Authored-By: Claude Opus 4.6 --- .../domain/gis/service/GisServiceV2.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java b/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java index 1bc335d..ecefb2b 100644 --- a/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java +++ b/src/main/java/gc/mda/signal_batch/domain/gis/service/GisServiceV2.java @@ -360,7 +360,7 @@ public class GisServiceV2 { } } - // 3-a. hourly 범위 → L2 캐시 → DB fallback + // 3-a. hourly 범위 → L2 캐시 → DB fallback (누락 MMSI 부분 fallback 포함) if (split.hasHourlyRange()) { DailyTrackCacheManager.DateRange hr = split.getHourlyRange(); Map> hourlyTracks = @@ -373,6 +373,19 @@ public class GisServiceV2 { int totalPts = converted.stream().mapToInt(CompactVesselTrack::getPointCount).sum(); log.info("[CACHE-MONITOR] queryWithCache L2 HIT [{}, {}): cacheVessels={}, filteredVessels={}, compactTracks={}, points={}", hr.getStart(), hr.getEnd(), hourlyTracks.size(), filtered.size(), converted.size(), totalPts); + + // 캐시에 없는 MMSI → DB fallback + Set missingMmsis = new HashSet<>(requestedMmsis); + missingMmsis.removeAll(filtered.keySet()); + if (!missingMmsis.isEmpty()) { + VesselTracksRequest fallbackReq = VesselTracksRequest.builder() + .startTime(hr.getStart()).endTime(hr.getEnd()) + .vessels(new ArrayList<>(missingMmsis)).build(); + List dbResult = gisService.getVesselTracks(fallbackReq); + allTracks.addAll(dbResult); + log.info("[CACHE-MONITOR] queryWithCache L2 PARTIAL → DB fallback: cacheHit={}, cacheMiss={}, dbTracks={}", + filtered.size(), missingMmsis.size(), dbResult.size()); + } } else { VesselTracksRequest hourlyReq = VesselTracksRequest.builder() .startTime(hr.getStart()).endTime(hr.getEnd()) @@ -384,7 +397,7 @@ public class GisServiceV2 { } } - // 3-b. 5min 범위 → L1 캐시 → DB fallback + // 3-b. 5min 범위 → L1 캐시 → DB fallback (누락 MMSI 부분 fallback 포함) if (split.hasFiveMinRange()) { DailyTrackCacheManager.DateRange fr = split.getFiveMinRange(); Map> fiveMinTracks = @@ -397,6 +410,19 @@ public class GisServiceV2 { int totalPts = converted.stream().mapToInt(CompactVesselTrack::getPointCount).sum(); log.info("[CACHE-MONITOR] queryWithCache L1 HIT [{}, {}): cacheVessels={}, filteredVessels={}, compactTracks={}, points={}", fr.getStart(), fr.getEnd(), fiveMinTracks.size(), filtered.size(), converted.size(), totalPts); + + // 캐시에 없는 MMSI → DB fallback + Set missingMmsis = new HashSet<>(requestedMmsis); + missingMmsis.removeAll(filtered.keySet()); + if (!missingMmsis.isEmpty()) { + VesselTracksRequest fallbackReq = VesselTracksRequest.builder() + .startTime(fr.getStart()).endTime(fr.getEnd()) + .vessels(new ArrayList<>(missingMmsis)).build(); + List dbResult = gisService.getVesselTracks(fallbackReq); + allTracks.addAll(dbResult); + log.info("[CACHE-MONITOR] queryWithCache L1 PARTIAL → DB fallback: cacheHit={}, cacheMiss={}, dbTracks={}", + filtered.size(), missingMmsis.size(), dbResult.size()); + } } else { VesselTracksRequest fiveMinReq = VesselTracksRequest.builder() .startTime(fr.getStart()).endTime(fr.getEnd()) -- 2.45.2