From d384271a3037625d572dcefc2b3785ea737b2954 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 18:13:03 +0000 Subject: [PATCH] =?UTF-8?q?fix(meteo):=20r=C3=A9tablir=20les=20appels=20s?= =?UTF-8?q?=C3=A9quentiels=20=C3=A0=20l'API=20m=C3=A9t=C3=A9o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La comparaison avec l'année dernière avait disparu du widget météo depuis l'optimisation des chargements. La route /api/weather/current interrogeait Visual Crossing pour aujourd'hui et pour l'année dernière en parallèle : la seconde requête d'une même clé peut alors être refusée (limite de requêtes simultanées), laissant previousYear à null. Les deux appels redeviennent séquentiels comme avant ; seules les lectures du cache local restent en parallèle. Le widget retrouve son comportement d'origine (plus de cache de 30 minutes ni de retry désactivé), pour qu'un échec ponctuel ne masque plus la comparaison pendant une demi-heure. Les erreurs de l'API journalisent désormais la raison renvoyée par Visual Crossing (quota, plan, clé). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MsDJjQrAggcJwbbBtKhgyb --- client/src/components/WeatherWidget.tsx | 5 -- server/routes.ts | 83 ++++++++++++------------- server/weatherService.ts | 7 ++- 3 files changed, 45 insertions(+), 50 deletions(-) diff --git a/client/src/components/WeatherWidget.tsx b/client/src/components/WeatherWidget.tsx index 7b4cf61..6a93cf5 100644 --- a/client/src/components/WeatherWidget.tsx +++ b/client/src/components/WeatherWidget.tsx @@ -121,11 +121,6 @@ export default function WeatherWidget() { const { data: weather, isLoading, error } = useQuery({ queryKey: ['/api/weather/current'], refetchInterval: 30 * 60 * 1000, // Refetch every 30 minutes - // Données valables jusqu'au prochain rafraîchissement : pas de rechargement au remontage - staleTime: 30 * 60 * 1000, - // Pas de nouvel essai : un 404 (météo non configurée) ne changera pas, et le - // serveur peut appeler l'API météo externe à chaque requête - retry: false, }); diff --git a/server/routes.ts b/server/routes.ts index 8dd549d..4f05128 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -5421,58 +5421,55 @@ RÉSUMÉ DU SCAN const today = new Date().toISOString().split('T')[0]; const previousYearDate = weatherService.getPreviousYearDate(); - // Check if we already have today's data (deux lectures indépendantes) + // Lectures du cache indépendantes : en parallèle let [currentYearData, previousYearData] = await Promise.all([ storage.getWeatherData(today, true), storage.getWeatherData(previousYearDate, false), ]); - // Les appels à l'API pour l'année en cours et l'année précédente sont - // indépendants : ils sont lancés en parallèle - await Promise.all([ - (async () => { - // Fetch current year data if not in cache - if (!currentYearData) { - console.log("🌤️ [FETCH] Fetching current weather data from API"); - const apiData = await weatherService.fetchCurrentWeather(settings); - if (apiData) { - const weatherData = weatherService.convertApiDataToWeatherData(apiData, settings.location, true); - if (weatherData) { - try { - currentYearData = await storage.createWeatherData(weatherData); - console.log("✅ [CACHE] Current year data saved to cache"); - } catch (error: any) { - console.warn("⚠️ [CACHE] Could not save current year data (may already exist):", error.message); - // Récupérer les données existantes au lieu de créer - currentYearData = await storage.getWeatherData(today, true); - } - } + // Les appels à l'API météo restent séquentiels : lancés en parallèle, + // Visual Crossing peut refuser la seconde requête d'une même clé (limite + // de requêtes simultanées) et la comparaison avec l'an dernier disparaît. + + // Fetch current year data if not in cache + if (!currentYearData) { + console.log("🌤️ [FETCH] Fetching current weather data from API"); + const apiData = await weatherService.fetchCurrentWeather(settings); + if (apiData) { + const weatherData = weatherService.convertApiDataToWeatherData(apiData, settings.location, true); + if (weatherData) { + try { + currentYearData = await storage.createWeatherData(weatherData); + console.log("✅ [CACHE] Current year data saved to cache"); + } catch (error: any) { + console.warn("⚠️ [CACHE] Could not save current year data (may already exist):", error.message); + // Récupérer les données existantes au lieu de créer + currentYearData = await storage.getWeatherData(today, true); } } - })(), - (async () => { - // Fetch previous year data if not in cache - if (!previousYearData) { - console.log("🌤️ [FETCH] Fetching previous year weather data from API"); - const apiData = await weatherService.fetchPreviousYearWeather(settings, previousYearDate); - if (apiData) { - const weatherData = weatherService.convertApiDataToWeatherData(apiData, settings.location, false); - if (weatherData) { - try { - previousYearData = await storage.createWeatherData(weatherData); - console.log("✅ [CACHE] Previous year data saved to cache"); - } catch (error: any) { - console.warn("⚠️ [CACHE] Could not save previous year data (may already exist):", error.message); - // Récupérer les données existantes au lieu de créer - previousYearData = await storage.getWeatherData(previousYearDate, false); - } - } - } else { - console.warn("⚠️ [HISTORY] Could not fetch historical data - continuing with current year only"); + } + } + + // Fetch previous year data if not in cache + if (!previousYearData) { + console.log("🌤️ [FETCH] Fetching previous year weather data from API"); + const apiData = await weatherService.fetchPreviousYearWeather(settings, previousYearDate); + if (apiData) { + const weatherData = weatherService.convertApiDataToWeatherData(apiData, settings.location, false); + if (weatherData) { + try { + previousYearData = await storage.createWeatherData(weatherData); + console.log("✅ [CACHE] Previous year data saved to cache"); + } catch (error: any) { + console.warn("⚠️ [CACHE] Could not save previous year data (may already exist):", error.message); + // Récupérer les données existantes au lieu de créer + previousYearData = await storage.getWeatherData(previousYearDate, false); } } - })(), - ]); + } else { + console.warn("⚠️ [HISTORY] Could not fetch historical data - continuing with current year only"); + } + } // Repli : si l'API historique a échoué (quota épuisé, panne, plan sans // accès à l'historique), reprendre la ligne en cache la plus proche de diff --git a/server/weatherService.ts b/server/weatherService.ts index 31bc58d..8a681d4 100644 --- a/server/weatherService.ts +++ b/server/weatherService.ts @@ -27,7 +27,8 @@ export class WeatherService { const response = await fetch(url); if (!response.ok) { - console.error(`Weather API error: ${response.status} ${response.statusText}`); + const reason = (await response.text().catch(() => '')).slice(0, 300); + console.error(`Weather API error: ${response.status} ${response.statusText} ${reason}`); return null; } @@ -51,7 +52,9 @@ export class WeatherService { const response = await fetch(url); if (!response.ok) { - console.error(`🌤️ [ERROR] Weather API error for previous year: ${response.status} ${response.statusText}`); + // Visual Crossing explique le refus dans le corps (quota, plan, clé...) + const reason = (await response.text().catch(() => '')).slice(0, 300); + console.error(`🌤️ [ERROR] Weather API error for previous year: ${response.status} ${response.statusText} ${reason}`); // Pour les données historiques, certains comptes peuvent ne pas avoir accès if (response.status === 401) {