fix: [dashboard] 주간 날씨 중기예보 데이터 누락 수정

- 18시 발표 중기예보 미발행 시 06시/전일 발표로 fallback
- 불완전한 날씨 데이터 캐시 TTL 10분으로 단축 (기존 3시간)
This commit is contained in:
김보곤
2026-02-22 18:54:27 +09:00
parent a412164fac
commit 14c9b787e9

View File

@@ -33,7 +33,7 @@ public function __construct()
}
/**
* 7일 예보 데이터 반환 (3시간 캐시)
* 7일 예보 데이터 반환 (완전한 데이터 3시간, 불완전 10분 캐시)
*/
public function getWeeklyForecast(): array
{
@@ -41,15 +41,26 @@ public function getWeeklyForecast(): array
return [];
}
return Cache::remember('weather_forecast_7days', 10800, function () {
try {
return $this->buildForecast();
} catch (\Throwable $e) {
Log::warning('WeatherService: 예보 조합 실패', ['error' => $e->getMessage()]);
$cached = Cache::get('weather_forecast_7days');
if ($cached !== null) {
return $cached;
}
return [];
}
});
try {
$forecasts = $this->buildForecast();
} catch (\Throwable $e) {
Log::warning('WeatherService: 예보 조합 실패', ['error' => $e->getMessage()]);
return [];
}
// 데이터 없는 날이 있으면 10분만 캐시 (API 재시도 유도)
$hasIncomplete = collect($forecasts)->contains(
fn ($fc) => $fc['tmn'] === null && $fc['tmx'] === null && $fc['icon'] === null
);
Cache::put('weather_forecast_7days', $forecasts, $hasIncomplete ? 600 : 10800);
return $forecasts;
}
private function buildForecast(): array
@@ -190,61 +201,72 @@ private function fetchShortForecast(): array
}
/**
* 중기기온 API 호출
* 중기기온 API 호출 (18시 발표 실패 시 06시 fallback)
*/
private function fetchMidTemperature(): array
{
$body = $this->callApi(self::BASE_MID_TA, [
'pageNo' => 1,
'numOfRows' => 10,
'regId' => self::MID_TA_REG_ID,
'tmFc' => $this->getMidBaseTmFc(),
]);
$tmFcList = $this->getMidBaseTmFcCandidates();
if (! $body) {
return [];
foreach ($tmFcList as $tmFc) {
$body = $this->callApi(self::BASE_MID_TA, [
'pageNo' => 1,
'numOfRows' => 10,
'regId' => self::MID_TA_REG_ID,
'tmFc' => $tmFc,
]);
$items = $body ? data_get($body, 'response.body.items.item', []) : [];
if (! empty($items)) {
return $items[0];
}
}
$items = data_get($body, 'response.body.items.item', []);
return $items[0] ?? [];
return [];
}
/**
* 중기날씨 API 호출
* 중기날씨 API 호출 (18시 발표 실패 시 06시 fallback)
*/
private function fetchMidLandForecast(): array
{
$body = $this->callApi(self::BASE_MID_LAND, [
'pageNo' => 1,
'numOfRows' => 10,
'regId' => self::MID_LAND_REG_ID,
'tmFc' => $this->getMidBaseTmFc(),
]);
$tmFcList = $this->getMidBaseTmFcCandidates();
if (! $body) {
return [];
foreach ($tmFcList as $tmFc) {
$body = $this->callApi(self::BASE_MID_LAND, [
'pageNo' => 1,
'numOfRows' => 10,
'regId' => self::MID_LAND_REG_ID,
'tmFc' => $tmFc,
]);
$items = $body ? data_get($body, 'response.body.items.item', []) : [];
if (! empty($items)) {
return $items[0];
}
}
$items = data_get($body, 'response.body.items.item', []);
return $items[0] ?? [];
return [];
}
/**
* 중기예보 발표시각 (06시/18시 기준)
* 중기예보 발표시각 후보 목록 (우선순위순, fallback 포함)
*/
private function getMidBaseTmFc(): string
private function getMidBaseTmFcCandidates(): array
{
$now = Carbon::now();
$today = $now->format('Ymd');
$yesterday = $now->copy()->subDay()->format('Ymd');
if ($now->hour >= 18) {
return $now->format('Ymd').'1800';
// 18시 발표 → 06시 발표 → 전일 18시 발표
return [$today.'1800', $today.'0600', $yesterday.'1800'];
} elseif ($now->hour >= 6) {
return $now->format('Ymd').'0600';
// 06시 발표 → 전일 18시 발표
return [$today.'0600', $yesterday.'1800'];
}
return $now->copy()->subDay()->format('Ymd').'1800';
// 자정~06시: 전일 18시 발표 → 전일 06시 발표
return [$yesterday.'1800', $yesterday.'0600'];
}
/**