fix: 기상청 API 호출 제한에도 날씨 캐시 유지#2292
Conversation
- 동시 호출 제한을 일반 외부 API 오류와 분리해 재시도 대상이 불필요하게 넓어지는 것을 방지 - 최초 호출 이후 5초 간격으로 5회만 추가 시도하도록 날씨 전용 RetryTemplate을 구성 - 전역 @EnableRetry 없이 날씨 클라이언트에만 정책을 주입해 기존 Slack, SMS, 메일 동작에 영향을 주지 않도록 제한
- 갱신 시점부터 향후 24시간 예보를 yyyyMMddHHmm 기준 Map으로 묶어 날짜 경계를 넘는 시간대도 함께 보관 - Redis 단일 키의 TTL을 24시간으로 늘리고 조회 요청은 현재 정시 예보만 선택해 외부 API와 사용자 요청을 분리 - HTTP 429와 기상청 초당 요청 제한 응답만 전용 예외로 분류해 5초 간격 5회 재시도를 적용 - 모든 갱신 시도가 실패하면 저장을 수행하지 않아 기존 캐시가 삭제되거나 불완전한 데이터로 교체되는 상황을 방지 - 24시간 범위 경계, 재시도 횟수, 현재 시간 조회와 Redis 직렬화를 단위 및 인수 테스트로 검증
📝 WalkthroughWalkthroughIntroduces ChangesWeather hourly forecast map and rate-limit retry
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/in/koreatech/koin/domain/weather/config/WeatherRetryConfig.java (1)
18-21: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winPrefer jittered backoff for the 429 retry path.
A fixed 5-second delay makes every instance that gets throttled retry in lockstep, which can recreate the same burst against KMA. Randomized or exponential backoff is a better fit for the rate-limit scenario this PR is addressing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/in/koreatech/koin/domain/weather/config/WeatherRetryConfig.java` around lines 18 - 21, The retry setup in WeatherRetryConfig uses a fixed backoff for WeatherOpenApiRateLimitException, which causes synchronized retries under 429 throttling. Update the RetryTemplate builder in the retry configuration to use jittered or exponential backoff instead of fixedBackoff, keeping the retryOn(WeatherOpenApiRateLimitException.class) behavior intact and adjusting the retry interval settings accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/in/koreatech/koin/domain/weather/client/WeatherClient.java`:
- Around line 42-44: The cached forecast window in WeatherClient is ending too
early relative to the Redis TTL, so WeatherService.getWeather() can request an
hour that is still within the cache lifetime but missing from the stored data.
Update the forecast-window logic in WeatherClient to include the final boundary
hour or, alternatively, make the cache expiration align with the exact forecast
boundary instead of a fixed 24h TTL. Check the filtering/range construction
around FORECAST_RANGE_HOURS and the cache save/expiration path so the last
partial hour is always covered.
---
Nitpick comments:
In
`@src/main/java/in/koreatech/koin/domain/weather/config/WeatherRetryConfig.java`:
- Around line 18-21: The retry setup in WeatherRetryConfig uses a fixed backoff
for WeatherOpenApiRateLimitException, which causes synchronized retries under
429 throttling. Update the RetryTemplate builder in the retry configuration to
use jittered or exponential backoff instead of fixedBackoff, keeping the
retryOn(WeatherOpenApiRateLimitException.class) behavior intact and adjusting
the retry interval settings accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f5d623f9-e3d2-4ea7-ba40-f9053c53f405
📒 Files selected for processing (9)
src/main/java/in/koreatech/koin/domain/weather/client/WeatherClient.javasrc/main/java/in/koreatech/koin/domain/weather/config/WeatherRetryConfig.javasrc/main/java/in/koreatech/koin/domain/weather/exception/WeatherOpenApiException.javasrc/main/java/in/koreatech/koin/domain/weather/exception/WeatherOpenApiRateLimitException.javasrc/main/java/in/koreatech/koin/domain/weather/model/WeatherCache.javasrc/main/java/in/koreatech/koin/domain/weather/service/WeatherService.javasrc/test/java/in/koreatech/koin/acceptance/domain/WeatherApiTest.javasrc/test/java/in/koreatech/koin/unit/domain/weather/WeatherClientTest.javasrc/test/java/in/koreatech/koin/unit/domain/weather/WeatherServiceTest.java
| private static final int FORECAST_RANGE_HOURS = 24; | ||
| private static final DateTimeFormatter FORECAST_DATE_TIME_FORMATTER = | ||
| DateTimeFormatter.ofPattern("yyyyMMddHHmm"); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Cover the TTL’s final partial hour in the cached forecast window.
With [start, start + 24h) filtering and a 24h Redis TTL, a cache saved at e.g. 03:35 contains slots through 02:00 next day, but remains alive until 03:35; WeatherService.getWeather() then throws for 03:00 because that key is missing. Include the boundary hour or expire the cache at the forecast window boundary.
Proposed fix
- private static final int FORECAST_RANGE_HOURS = 24;
+ private static final int FORECAST_RANGE_HOURS = 25;- // 달력 날짜가 아닌 갱신 시각을 기준으로 향후 24시간의 예보만 캐시에 저장한다.
+ // 달력 날짜가 아닌 갱신 시각을 기준으로 캐시 TTL 마지막 시간대까지 예보를 저장한다.Also applies to: 82-89
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/in/koreatech/koin/domain/weather/client/WeatherClient.java`
around lines 42 - 44, The cached forecast window in WeatherClient is ending too
early relative to the Redis TTL, so WeatherService.getWeather() can request an
hour that is still within the cache lifetime but missing from the stored data.
Update the forecast-window logic in WeatherClient to include the final boundary
hour or, alternatively, make the cache expiration align with the exact forecast
boundary instead of a fixed 24h TTL. Check the filtering/range construction
around FORECAST_RANGE_HOURS and the cache save/expiration path so the last
partial hour is always covered.
🔍 개요
🚀 주요 변경 내용
/weather요청은 외부 API를 호출하지 않고 현재 정시의 예보만 캐시에서 선택하며, 공개 응답 형식은 유지합니다.💬 참고 사항
@EnableRetry를 사용하지 않고 날씨 전용RetryTemplate을 구성해 기존 Slack, SMS, 메일 재시도 동작에 영향을 주지 않습니다../gradlew check --rerun-tasks --no-daemon으로 단위 테스트, Redis 인수 테스트와 전체 회귀 테스트를 검증했습니다.✅ Checklist (완료 조건)
Summary by CodeRabbit
New Features
Bug Fixes