优化管家婆缓存状态批量查询
This commit is contained in:
parent
53b52995df
commit
c31e394558
@ -79,9 +79,10 @@ public class NgpMonthlyWeeklyService {
|
||||
LocalDate monthEnd = month.atEndOfMonth();
|
||||
LocalDate dataEnd = month.equals(currentMonth) ? today : monthEnd;
|
||||
LocalDateTime now = LocalDateTime.now(clock);
|
||||
Map<LocalDate, LocalDateTime> storedRefreshTimes = repository.findRefreshTimes(monthStart, dataEnd);
|
||||
Map<LocalDate, LocalDateTime> cachedDates = new LinkedHashMap<>();
|
||||
monthStart.datesUntil(dataEnd.plusDays(1)).forEach(date ->
|
||||
cachedDates.put(date, repository.findRefreshTime(date).orElse(null)));
|
||||
cachedDates.put(date, storedRefreshTimes.get(date)));
|
||||
List<LocalDate> missingDates = cachedDates.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() == null)
|
||||
.map(Map.Entry::getKey)
|
||||
|
||||
@ -62,6 +62,26 @@ public class NgpPerformanceCacheRepository {
|
||||
return rows.stream().findFirst();
|
||||
}
|
||||
|
||||
public Map<LocalDate, LocalDateTime> findRefreshTimes(LocalDate startDate, LocalDate endDate) {
|
||||
Map<LocalDate, LocalDateTime> result = new LinkedHashMap<>();
|
||||
jdbcTemplate.query("""
|
||||
SELECT business_date, refreshed_at
|
||||
FROM ngp_performance_daily_status
|
||||
WHERE business_date BETWEEN ? AND ?
|
||||
AND filter_signature = ?
|
||||
ORDER BY business_date
|
||||
""",
|
||||
(RowCallbackHandler) resultSet -> result.put(
|
||||
resultSet.getObject("business_date", LocalDate.class),
|
||||
resultSet.getTimestamp("refreshed_at").toLocalDateTime()
|
||||
),
|
||||
startDate,
|
||||
endDate,
|
||||
FILTER_SIGNATURE
|
||||
);
|
||||
return Map.copyOf(result);
|
||||
}
|
||||
|
||||
public Map<String, NgpStoreTotal> aggregate(LocalDate startDate, LocalDate endDate) {
|
||||
Map<String, NgpStoreTotal> result = new LinkedHashMap<>();
|
||||
jdbcTemplate.query("""
|
||||
|
||||
@ -46,9 +46,11 @@ public class NgpPerformanceTotalService {
|
||||
public NgpPerformanceResult total(NgpPerformanceTotalRequest request) {
|
||||
validate(request);
|
||||
LocalDateTime now = LocalDateTime.now(BUSINESS_ZONE);
|
||||
Map<LocalDate, LocalDateTime> storedRefreshTimes = repository.findRefreshTimes(
|
||||
request.startDate(), request.endDate());
|
||||
Map<LocalDate, LocalDateTime> cachedDates = new LinkedHashMap<>();
|
||||
request.startDate().datesUntil(request.endDate().plusDays(1)).forEach(date ->
|
||||
cachedDates.put(date, repository.findRefreshTime(date).orElse(null)));
|
||||
cachedDates.put(date, storedRefreshTimes.get(date)));
|
||||
List<LocalDate> missingDates = cachedDates.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() == null)
|
||||
.map(Map.Entry::getKey)
|
||||
|
||||
@ -16,13 +16,13 @@ import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ -45,7 +45,7 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
|
||||
@Test
|
||||
void currentMonthOnlyRequiresDatesThroughToday() {
|
||||
when(repository.findRefreshTime(any())).thenReturn(Optional.empty());
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(Map.of());
|
||||
|
||||
NgpMonthlyWeeklyResult result = service.query(new NgpMonthlyWeeklyRequest(null, null, null));
|
||||
|
||||
@ -57,12 +57,13 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
LocalDate.of(2026, 9, 1), LocalDate.of(2026, 9, 2), LocalDate.of(2026, 9, 3),
|
||||
LocalDate.of(2026, 9, 4), LocalDate.of(2026, 9, 5), LocalDate.of(2026, 9, 6),
|
||||
LocalDate.of(2026, 9, 7), LocalDate.of(2026, 9, 8), LocalDate.of(2026, 9, 9));
|
||||
verify(repository, times(9)).findRefreshTime(any());
|
||||
verify(repository).findRefreshTimes(LocalDate.of(2026, 9, 1), LocalDate.of(2026, 9, 9));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildsMondayToSundayColumnsAndStoreSubtotalsFromDailyCache() {
|
||||
when(repository.findRefreshTime(any())).thenReturn(Optional.of(LocalDateTime.of(2026, 9, 9, 11, 59)));
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(
|
||||
currentMonthRefreshTimes(LocalDateTime.of(2026, 9, 9, 11, 59)));
|
||||
when(repository.findDailyTotals(any(), any())).thenReturn(List.of(
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 1), "a", "网点A", 10000),
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 6), "a", "网点A", 20000),
|
||||
@ -86,7 +87,8 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
|
||||
@Test
|
||||
void keepsRequestedStoreOrderAndExcludesOtherStores() {
|
||||
when(repository.findRefreshTime(any())).thenReturn(Optional.of(LocalDateTime.of(2026, 9, 9, 11, 59)));
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(
|
||||
currentMonthRefreshTimes(LocalDateTime.of(2026, 9, 9, 11, 59)));
|
||||
when(repository.findDailyTotals(any(), any())).thenReturn(List.of(
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 1), "网点a", "网点A", 10000),
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 1), "其他网点", "其他网点", 99900)
|
||||
@ -106,7 +108,8 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
|
||||
@Test
|
||||
void acceptsCommaSeparatedStoreNameAndQueriesAllWhenItIsBlank() {
|
||||
when(repository.findRefreshTime(any())).thenReturn(Optional.of(LocalDateTime.of(2026, 9, 9, 11, 59)));
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(
|
||||
currentMonthRefreshTimes(LocalDateTime.of(2026, 9, 9, 11, 59)));
|
||||
when(repository.findDailyTotals(any(), any())).thenReturn(List.of(
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 1), "网点a", "网点A", 10000),
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 1), "网点b", "网点B", 20000),
|
||||
@ -128,8 +131,8 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
|
||||
@Test
|
||||
void returnsStaleMonthlyCacheWhileRefreshingInBackground() {
|
||||
when(repository.findRefreshTime(any()))
|
||||
.thenReturn(Optional.of(LocalDateTime.of(2026, 9, 7, 12, 0)));
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(
|
||||
currentMonthRefreshTimes(LocalDateTime.of(2026, 9, 7, 12, 0)));
|
||||
when(repository.findDailyTotals(any(), any())).thenReturn(List.of(
|
||||
new NgpDailyStoreTotal(LocalDate.of(2026, 9, 1), "网点a", "网点A", 12345)
|
||||
));
|
||||
@ -155,4 +158,11 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
assertThat(context.getBean(NgpMonthlyWeeklyService.class)).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<LocalDate, LocalDateTime> currentMonthRefreshTimes(LocalDateTime refreshedAt) {
|
||||
Map<LocalDate, LocalDateTime> result = new LinkedHashMap<>();
|
||||
LocalDate.of(2026, 9, 1).datesUntil(LocalDate.of(2026, 9, 10))
|
||||
.forEach(date -> result.put(date, refreshedAt));
|
||||
return Map.copyOf(result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.company.agentfoundation.ngp.performance;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@ -37,4 +38,22 @@ class NgpPerformanceCacheRepositoryTest {
|
||||
eq(NgpPerformanceCacheRepository.FILTER_SIGNATURE)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadsRefreshTimesForTheWholeDateRangeInOneQuery() {
|
||||
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
||||
NgpPerformanceCacheRepository repository = new NgpPerformanceCacheRepository(jdbcTemplate);
|
||||
LocalDate startDate = LocalDate.of(2026, 9, 1);
|
||||
LocalDate endDate = LocalDate.of(2026, 9, 24);
|
||||
|
||||
repository.findRefreshTimes(startDate, endDate);
|
||||
|
||||
verify(jdbcTemplate).query(
|
||||
contains("business_date BETWEEN ? AND ?"),
|
||||
any(RowCallbackHandler.class),
|
||||
eq(startDate),
|
||||
eq(endDate),
|
||||
eq(NgpPerformanceCacheRepository.FILTER_SIGNATURE)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import org.junit.jupiter.api.Test;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@ -32,7 +31,7 @@ class NgpPerformanceTotalServiceTest {
|
||||
|
||||
@Test
|
||||
void returnsPendingAndStartsRefreshWhenAnyDayIsMissing() {
|
||||
when(repository.findRefreshTime(any())).thenReturn(Optional.empty());
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(Map.of());
|
||||
|
||||
NgpPerformanceResult result = service.total(new NgpPerformanceTotalRequest(
|
||||
LocalDate.of(2026, 9, 1), LocalDate.of(2026, 9, 6), null));
|
||||
@ -46,7 +45,8 @@ class NgpPerformanceTotalServiceTest {
|
||||
|
||||
@Test
|
||||
void returnsCachedTotalAndFiltersUniquePartialStoreName() {
|
||||
when(repository.findRefreshTime(any())).thenReturn(Optional.of(LocalDateTime.now()));
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(refreshTimes(
|
||||
LocalDate.of(2026, 9, 1), LocalDate.of(2026, 9, 6), LocalDateTime.now()));
|
||||
when(repository.aggregate(any(), any())).thenReturn(Map.of(
|
||||
NgpPerformanceDayLoader.normalize("兰教练(抖店)"), new NgpStoreTotal("兰教练(抖店)", 490866847L),
|
||||
NgpPerformanceDayLoader.normalize("另一个网点"), new NgpStoreTotal("另一个网点", 200L)
|
||||
@ -63,8 +63,9 @@ class NgpPerformanceTotalServiceTest {
|
||||
|
||||
@Test
|
||||
void returnsStaleCachedTotalWhileRefreshingInBackground() {
|
||||
when(repository.findRefreshTime(any()))
|
||||
.thenReturn(Optional.of(LocalDateTime.now().minusDays(2)));
|
||||
when(repository.findRefreshTimes(any(), any())).thenReturn(refreshTimes(
|
||||
LocalDate.now().minusDays(3), LocalDate.now().minusDays(2),
|
||||
LocalDateTime.now().minusDays(2)));
|
||||
when(repository.aggregate(any(), any())).thenReturn(Map.of(
|
||||
NgpPerformanceDayLoader.normalize("网点A"), new NgpStoreTotal("网点A", 12345L)
|
||||
));
|
||||
@ -76,4 +77,14 @@ class NgpPerformanceTotalServiceTest {
|
||||
assertThat(((NgpPerformanceTotalResponse) result).totalAmount()).isEqualByComparingTo("123.45");
|
||||
verify(coordinator).ensureRefresh(any());
|
||||
}
|
||||
|
||||
private Map<LocalDate, LocalDateTime> refreshTimes(
|
||||
LocalDate startDate,
|
||||
LocalDate endDate,
|
||||
LocalDateTime refreshedAt
|
||||
) {
|
||||
Map<LocalDate, LocalDateTime> result = new java.util.LinkedHashMap<>();
|
||||
startDate.datesUntil(endDate.plusDays(1)).forEach(date -> result.put(date, refreshedAt));
|
||||
return Map.copyOf(result);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user