Merge pull request 'fix: UTC 타임존 변환 + Daily 캐시 부분 fallback 추가' (#52) from feature/dashboard-phase-1 into develop
This commit is contained in:
커밋
f5738978ed
@ -24,6 +24,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -327,7 +328,7 @@ public class GisServiceV2 {
|
|||||||
|
|
||||||
Set<String> requestedMmsis = new HashSet<>(request.getVessels());
|
Set<String> requestedMmsis = new HashSet<>(request.getVessels());
|
||||||
|
|
||||||
// 1. 캐시에서 조회 (캐시된 날짜)
|
// 1. 캐시에서 조회 (캐시된 날짜) + 누락 MMSI 부분 DB fallback
|
||||||
if (split.hasCachedData()) {
|
if (split.hasCachedData()) {
|
||||||
List<CompactVesselTrack> cachedTracks =
|
List<CompactVesselTrack> cachedTracks =
|
||||||
dailyTrackCacheManager.getCachedTracksMultipleDays(split.getCachedDates());
|
dailyTrackCacheManager.getCachedTracksMultipleDays(split.getCachedDates());
|
||||||
@ -343,6 +344,28 @@ public class GisServiceV2 {
|
|||||||
allTracks.addAll(filteredCached);
|
allTracks.addAll(filteredCached);
|
||||||
log.debug("[CacheQuery] cached {} days -> {} tracks (filtered from {})",
|
log.debug("[CacheQuery] cached {} days -> {} tracks (filtered from {})",
|
||||||
split.getCachedDates().size(), filteredCached.size(), totalCachedCount);
|
split.getCachedDates().size(), filteredCached.size(), totalCachedCount);
|
||||||
|
|
||||||
|
// Daily 캐시에 없는 MMSI → DB fallback (hourly/5min 계층 조회)
|
||||||
|
Set<String> cachedMmsis = filteredCached.stream()
|
||||||
|
.map(CompactVesselTrack::getVesselId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<String> missingMmsis = new HashSet<>(requestedMmsis);
|
||||||
|
missingMmsis.removeAll(cachedMmsis);
|
||||||
|
if (!missingMmsis.isEmpty()) {
|
||||||
|
LocalDate minDate = split.getCachedDates().stream().min(Comparator.naturalOrder()).orElse(null);
|
||||||
|
LocalDate maxDate = split.getCachedDates().stream().max(Comparator.naturalOrder()).orElse(null);
|
||||||
|
if (minDate != null) {
|
||||||
|
LocalDateTime cacheStart = minDate.atStartOfDay().isBefore(startTime) ? startTime : minDate.atStartOfDay();
|
||||||
|
LocalDateTime cacheEnd = maxDate.plusDays(1).atStartOfDay().isAfter(endTime) ? endTime : maxDate.plusDays(1).atStartOfDay();
|
||||||
|
VesselTracksRequest fallbackReq = VesselTracksRequest.builder()
|
||||||
|
.startTime(cacheStart).endTime(cacheEnd)
|
||||||
|
.vessels(new ArrayList<>(missingMmsis)).build();
|
||||||
|
List<CompactVesselTrack> dbResult = gisService.getVesselTracks(fallbackReq);
|
||||||
|
allTracks.addAll(dbResult);
|
||||||
|
log.info("[CACHE-MONITOR] queryWithCache daily PARTIAL → DB fallback: cacheHit={}, cacheMiss={}, dbTracks={}",
|
||||||
|
cachedMmsis.size(), missingMmsis.size(), dbResult.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. DB에서 조회 (캐시 미적중 과거 날짜)
|
// 2. DB에서 조회 (캐시 미적중 과거 날짜)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package gc.mda.signal_batch.global.util;
|
package gc.mda.signal_batch.global.util;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
@ -76,11 +77,12 @@ public class DateTimeParseUtil {
|
|||||||
String trimmed = dateTimeString.trim();
|
String trimmed = dateTimeString.trim();
|
||||||
|
|
||||||
// Try zoned formatters first for Z or offset patterns
|
// Try zoned formatters first for Z or offset patterns
|
||||||
|
// UTC/Offset → 시스템 타임존(KST)으로 변환 후 LocalDateTime 추출
|
||||||
if (trimmed.contains("Z") || trimmed.matches(".*[+-]\\d{2}:\\d{2}$")) {
|
if (trimmed.contains("Z") || trimmed.matches(".*[+-]\\d{2}:\\d{2}$")) {
|
||||||
for (DateTimeFormatter formatter : ZONED_FORMATTERS) {
|
for (DateTimeFormatter formatter : ZONED_FORMATTERS) {
|
||||||
try {
|
try {
|
||||||
ZonedDateTime zdt = ZonedDateTime.parse(trimmed, formatter);
|
ZonedDateTime zdt = ZonedDateTime.parse(trimmed, formatter);
|
||||||
return zdt.toLocalDateTime();
|
return zdt.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
|
||||||
} catch (DateTimeParseException ignored) {
|
} catch (DateTimeParseException ignored) {
|
||||||
// Try next formatter
|
// Try next formatter
|
||||||
}
|
}
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user