fix(server): handle daily password fetch errors

- Wrap the upstream call so connection and HTTP failures surface
  as 502 Bad Gateway instead of unhandled exceptions
- Return 502 Bad Gateway when the upstream payload is empty
- Expire the cached password at midnight rather than after 24 hours
This commit is contained in:
siujamo committed 2026-09-10 16:35:07 +08:00
1 parent d8b3ad2dee
commit ee7b96532d
1 file changed
+31 -12
@@ -8,12 +8,16 @@ import com.onixbyte.ahsarahguide.exeption.InternalServerErrorException;
import com.onixbyte.ahsarahguide.shared.JacksonModules;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.server.ResponseStatusException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Objects;
/**
@@ -60,25 +64,40 @@ public class DailyPasswordManager {
public DailyPasswordResponse getDailyPassword() {
var key = CACHE_KEY_PREFIX + LocalDate.now();
// Attempt to fetch the cached response
var cached = redisTemplate.opsForValue().get(key);
if (cached != null) {
return (DailyPasswordResponse) cached;
}
var response = restClient.get()
.uri((uriBuilder) -> uriBuilder
.path("/sjzmm")
.queryParam("ckey", "")
.queryParam("type", "json")
.build())
.retrieve()
.body(DailyPasswordResponse.class);
if (Objects.isNull(response)) {
throw new InternalServerErrorException("暂无每日密码数据。");
DailyPasswordResponse response;
try {
// Fetch from the upstream remote service
response = restClient.get()
.uri((uriBuilder) -> uriBuilder
.path("/sjzmm")
.queryParam("ckey", "")
.queryParam("type", "json")
.build())
.retrieve()
.body(DailyPasswordResponse.class);
} catch (Exception e) {
// Catch network errors, timeouts, or 4xx/5xx responses from the upstream service
throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "Failed to connect to the upstream service.", e);
}
redisTemplate.opsForValue().set(key, response, Duration.ofDays(1L));
if (Objects.isNull(response)) {
throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "No daily password data available.");
}
// Calculate the precise duration until midnight to optimise Redis memory usage
var now = LocalDateTime.now();
var midnight = now.toLocalDate().atStartOfDay().plusDays(1);
var durationUntilMidnight = Duration.between(now, midnight);
// Save to Redis with the calculated TTL
redisTemplate.opsForValue().set(key, response, durationUntilMidnight);
return response;
}
}