fix(meteo): rétablir les appels séquentiels à l'API météo

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MsDJjQrAggcJwbbBtKhgyb
This commit is contained in:
Claude committed 2026-10-04 18:13:03 +00:00
1 parent f4c582b217
commit d384271a30
3 files changed
+45 -50

No files matched your search

-5
View File
@@ -121,11 +121,6 @@ export default function WeatherWidget() {
const { data: weather, isLoading, error } = useQuery<WeatherResponse>({
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,
});
+40 -43
View File
@@ -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
+5 -2
View File
@@ -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) {