缓存更新
This commit is contained in:
parent
f0f74489ec
commit
0ba6a5b9e3
@ -5,6 +5,8 @@ import com.company.agentfoundation.ngp.performance.NgpDailyStoreTotal;
|
||||
import com.company.agentfoundation.ngp.performance.NgpPerformanceCacheRepository;
|
||||
import com.company.agentfoundation.ngp.performance.NgpPerformanceDayLoader;
|
||||
import com.company.agentfoundation.ngp.performance.NgpPerformanceRefreshCoordinator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -29,6 +31,7 @@ import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class NgpMonthlyWeeklyService {
|
||||
private static final Logger log = LoggerFactory.getLogger(NgpMonthlyWeeklyService.class);
|
||||
private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
|
||||
private static final String[] CHINESE_MONTHS = {
|
||||
"一月", "二月", "三月", "四月", "五月", "六月",
|
||||
@ -71,8 +74,12 @@ public class NgpMonthlyWeeklyService {
|
||||
LocalDate monthEnd = month.atEndOfMonth();
|
||||
LocalDate dataEnd = month.equals(currentMonth) ? today : monthEnd;
|
||||
LocalDateTime now = LocalDateTime.now(clock);
|
||||
List<LocalDate> missingDates = monthStart.datesUntil(dataEnd.plusDays(1))
|
||||
.filter(date -> !fresh(date, repository.findRefreshTime(date).orElse(null), now))
|
||||
Map<LocalDate, LocalDateTime> cachedDates = new LinkedHashMap<>();
|
||||
monthStart.datesUntil(dataEnd.plusDays(1)).forEach(date ->
|
||||
cachedDates.put(date, repository.findRefreshTime(date).orElse(null)));
|
||||
List<LocalDate> missingDates = cachedDates.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() == null)
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
if (!missingDates.isEmpty()) {
|
||||
refreshCoordinator.ensureRefresh(missingDates);
|
||||
@ -86,6 +93,11 @@ public class NgpMonthlyWeeklyService {
|
||||
retrySeconds
|
||||
);
|
||||
}
|
||||
List<LocalDate> staleDates = cachedDates.entrySet().stream()
|
||||
.filter(entry -> !fresh(entry.getKey(), entry.getValue(), now))
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
refreshStaleInBackground(staleDates);
|
||||
|
||||
List<NgpMonthlyWeek> weeks = buildWeeks(month, today);
|
||||
List<NgpDailyStoreTotal> dailyTotals = repository.findDailyTotals(monthStart, dataEnd);
|
||||
@ -240,6 +252,16 @@ public class NgpMonthlyWeeklyService {
|
||||
return Duration.between(refreshedAt, now).getSeconds() <= Math.max(ttlSeconds, 0);
|
||||
}
|
||||
|
||||
private void refreshStaleInBackground(List<LocalDate> staleDates) {
|
||||
if (staleDates.isEmpty()) return;
|
||||
try {
|
||||
refreshCoordinator.ensureRefresh(staleDates);
|
||||
} catch (RuntimeException exception) {
|
||||
log.warn("Serving stale NGP monthly cache after refresh scheduling failed dates={} err={}",
|
||||
staleDates.size(), exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private YearMonth parseMonth(String raw, YearMonth defaultMonth) {
|
||||
if (raw == null || raw.isBlank()) return defaultMonth;
|
||||
try {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.company.agentfoundation.ngp.performance;
|
||||
|
||||
import com.company.agentfoundation.config.FoundationProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -11,6 +13,7 @@ import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -19,6 +22,7 @@ import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class NgpPerformanceTotalService {
|
||||
private static final Logger log = LoggerFactory.getLogger(NgpPerformanceTotalService.class);
|
||||
private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
|
||||
private static final int MAX_RANGE_DAYS = 31;
|
||||
|
||||
@ -39,8 +43,12 @@ public class NgpPerformanceTotalService {
|
||||
public NgpPerformanceResult total(NgpPerformanceTotalRequest request) {
|
||||
validate(request);
|
||||
LocalDateTime now = LocalDateTime.now(BUSINESS_ZONE);
|
||||
List<LocalDate> missingDates = request.startDate().datesUntil(request.endDate().plusDays(1))
|
||||
.filter(date -> !fresh(date, repository.findRefreshTime(date).orElse(null), now))
|
||||
Map<LocalDate, LocalDateTime> cachedDates = new LinkedHashMap<>();
|
||||
request.startDate().datesUntil(request.endDate().plusDays(1)).forEach(date ->
|
||||
cachedDates.put(date, repository.findRefreshTime(date).orElse(null)));
|
||||
List<LocalDate> missingDates = cachedDates.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() == null)
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
if (!missingDates.isEmpty()) {
|
||||
refreshCoordinator.ensureRefresh(missingDates);
|
||||
@ -53,6 +61,11 @@ public class NgpPerformanceTotalService {
|
||||
retrySeconds
|
||||
);
|
||||
}
|
||||
List<LocalDate> staleDates = cachedDates.entrySet().stream()
|
||||
.filter(entry -> !fresh(entry.getKey(), entry.getValue(), now))
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
refreshStaleInBackground(staleDates);
|
||||
|
||||
String storeInput = request.storeName() == null ? "" : request.storeName().trim();
|
||||
Map<String, NgpStoreTotal> totals = repository.aggregate(request.startDate(), request.endDate());
|
||||
@ -76,6 +89,16 @@ public class NgpPerformanceTotalService {
|
||||
return Duration.between(refreshedAt, now).getSeconds() <= Math.max(ttlSeconds, 0);
|
||||
}
|
||||
|
||||
private void refreshStaleInBackground(List<LocalDate> staleDates) {
|
||||
if (staleDates.isEmpty()) return;
|
||||
try {
|
||||
refreshCoordinator.ensureRefresh(staleDates);
|
||||
} catch (RuntimeException exception) {
|
||||
log.warn("Serving stale NGP performance cache after refresh scheduling failed dates={} err={}",
|
||||
staleDates.size(), exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<NgpStoreTotal> selectStores(Map<String, NgpStoreTotal> stores, String storeInput) {
|
||||
if (storeInput.isBlank()) return List.copyOf(stores.values());
|
||||
Set<String> selectedKeys = new LinkedHashSet<>();
|
||||
|
||||
@ -122,6 +122,22 @@ class NgpMonthlyWeeklyServiceTest {
|
||||
assertThat(all.grandTotal()).isEqualByComparingTo("600.00");
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsStaleMonthlyCacheWhileRefreshingInBackground() {
|
||||
when(repository.findRefreshTime(any()))
|
||||
.thenReturn(Optional.of(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)
|
||||
));
|
||||
|
||||
NgpMonthlyWeeklyResult result = service.query(
|
||||
new NgpMonthlyWeeklyRequest("2026-09", null, null));
|
||||
|
||||
assertThat(result).isInstanceOf(NgpMonthlyWeeklyResponse.class);
|
||||
assertThat(((NgpMonthlyWeeklyResponse) result).grandTotal()).isEqualByComparingTo("123.45");
|
||||
verify(coordinator).ensureRefresh(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void springCanCreateServiceWhenTestClockConstructorAlsoExists() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
|
||||
@ -58,4 +58,20 @@ class NgpPerformanceTotalServiceTest {
|
||||
assertThat(response.totalAmount()).isEqualByComparingTo("4908668.47");
|
||||
assertThat(response.formattedTotal()).isEqualTo("4,908,668.47");
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsStaleCachedTotalWhileRefreshingInBackground() {
|
||||
when(repository.findRefreshTime(any()))
|
||||
.thenReturn(Optional.of(LocalDateTime.now().minusDays(2)));
|
||||
when(repository.aggregate(any(), any())).thenReturn(Map.of(
|
||||
NgpPerformanceDayLoader.normalize("网点A"), new NgpStoreTotal("网点A", 12345L)
|
||||
));
|
||||
|
||||
NgpPerformanceResult result = service.total(new NgpPerformanceTotalRequest(
|
||||
LocalDate.now().minusDays(3), LocalDate.now().minusDays(2), null));
|
||||
|
||||
assertThat(result).isInstanceOf(NgpPerformanceTotalResponse.class);
|
||||
assertThat(((NgpPerformanceTotalResponse) result).totalAmount()).isEqualByComparingTo("123.45");
|
||||
verify(coordinator).ensureRefresh(any());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user