fix(api): fix endpoint set concurrency and in-memory leaks (#7505)

This commit is contained in:
brios
2026-08-29 22:19:29 +01:00
committed by GitHub
parent 8bdd00b2fa
commit ddc0ac0ced
3 changed files with 18 additions and 21 deletions
@@ -48,7 +48,7 @@ public class EndpointConfiguration {
private final ApplicationProperties applicationProperties;
@Getter private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
private Set<String> disabledGroups = new HashSet<>();
private Set<String> disabledGroups = ConcurrentHashMap.newKeySet();
private Map<String, DisableReason> endpointDisableReasons = new ConcurrentHashMap<>();
private Map<String, DisableReason> groupDisableReasons = new ConcurrentHashMap<>();
private Map<String, Set<String>> endpointAlternatives = new ConcurrentHashMap<>();
@@ -4,7 +4,9 @@ import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@@ -21,7 +23,7 @@ public class WeeklyActiveUsersService {
private final Map<String, Instant> activeBrowsers = new ConcurrentHashMap<>();
// Track total unique browsers seen (overall)
private long totalUniqueBrowsers = 0;
private final AtomicLong totalUniqueBrowsers = new AtomicLong(0);
// Application start time
private final Instant startTime = Instant.now();
@@ -36,12 +38,12 @@ public class WeeklyActiveUsersService {
return;
}
boolean isNewBrowser = !activeBrowsers.containsKey(browserId);
activeBrowsers.put(browserId, Instant.now());
Instant now = Instant.now();
Instant previous = activeBrowsers.put(browserId, now);
if (isNewBrowser) {
totalUniqueBrowsers++;
log.debug("New browser recorded: {} (Total: {})", browserId, totalUniqueBrowsers);
if (previous == null) {
long total = totalUniqueBrowsers.incrementAndGet();
log.debug("New browser recorded: {} (Total: {})", browserId, total);
}
}
@@ -61,7 +63,7 @@ public class WeeklyActiveUsersService {
* @return Total unique browsers count
*/
public long getTotalUniqueBrowsers() {
return totalUniqueBrowsers;
return totalUniqueBrowsers.get();
}
/**
@@ -88,7 +90,8 @@ public class WeeklyActiveUsersService {
activeBrowsers.entrySet().removeIf(entry -> entry.getValue().isBefore(sevenDaysAgo));
}
/** Manual cleanup trigger (can be called by scheduled task if needed) */
/** Scheduled cleanup trigger running every hour */
@Scheduled(fixedRate = 3600000)
public void performCleanup() {
int sizeBefore = activeBrowsers.size();
cleanupOldEntries();
@@ -113,19 +113,13 @@ public class RateLimitService {
public void cleanupExpiredBuckets() {
long now = System.currentTimeMillis();
int hourlyRemoved =
(int)
hourlyLimits.entrySet().stream()
.filter(e -> e.getValue().getResetTime() < now)
.peek(e -> hourlyLimits.remove(e.getKey()))
.count();
int hourlyBefore = hourlyLimits.size();
hourlyLimits.entrySet().removeIf(e -> e.getValue().getResetTime() < now);
int hourlyRemoved = hourlyBefore - hourlyLimits.size();
int dailyRemoved =
(int)
dailyLimits.entrySet().stream()
.filter(e -> e.getValue().getResetTime() < now)
.peek(e -> dailyLimits.remove(e.getKey()))
.count();
int dailyBefore = dailyLimits.size();
dailyLimits.entrySet().removeIf(e -> e.getValue().getResetTime() < now);
int dailyRemoved = dailyBefore - dailyLimits.size();
if (hourlyRemoved + dailyRemoved > 0) {
log.debug(