fix: keep daily brief independent from warning checks

This commit is contained in:
zv
2026-06-12 21:43:34 +02:00
parent 763de7fd05
commit 1ff76cf847
3 changed files with 24 additions and 7 deletions

View File

@@ -9,6 +9,7 @@ const ALLOWED_PATHS = new Set([
"product",
]);
const IMGW_BASE_URL = "https://danepubliczne.imgw.pl/api/data";
const USER_AGENT = "wtr./1.0 (weather data proxy)";
export async function GET(_: Request, context: { params: Promise<{ path: string[] }> }) {
const { path } = await context.params;
@@ -24,7 +25,7 @@ export async function GET(_: Request, context: { params: Promise<{ path: string[
try {
const response = await fetch(`${IMGW_BASE_URL}/${upstreamPath}`, {
next: { revalidate: 300 },
headers: { Accept: "application/json" },
headers: { Accept: "application/json", "User-Agent": USER_AGENT },
});
if (!response.ok) {
return NextResponse.json({ error: "IMGW API jest chwilowo niedostępne." }, { status: response.status });

View File

@@ -2,14 +2,18 @@ import { normalizeWarning } from "@/lib/weather-utils";
import type { RawWarning, WeatherWarning } from "@/types/imgw";
const IMGW_WARNINGS_METEO_URL = "https://danepubliczne.imgw.pl/api/data/warningsmeteo";
const USER_AGENT = "wtr./1.0 (weather notification worker)";
export async function fetchMeteoWarnings(signal?: AbortSignal): Promise<WeatherWarning[]> {
const response = await fetch(IMGW_WARNINGS_METEO_URL, {
headers: { accept: "application/json" },
headers: { accept: "application/json", "user-agent": USER_AGENT },
next: { revalidate: 300 },
signal,
});
if (!response.ok) throw new Error("Unable to load IMGW meteorological warnings.");
if (!response.ok) {
const details = await response.text().catch(() => "");
throw new Error(`Unable to load IMGW meteorological warnings: ${response.status}${details ? ` ${details.slice(0, 240)}` : ""}`);
}
const rows = await response.json() as RawWarning[];
return Array.isArray(rows) ? rows.map((warning, index) => normalizeWarning(warning, "meteo", index)) : [];
}

View File

@@ -77,6 +77,16 @@ async function callNotificationEndpoint(path) {
return body;
}
async function callNotificationEndpointSafely(path) {
try {
await callNotificationEndpoint(path);
return true;
} catch (error) {
console.error(formatWorkerError(error));
return false;
}
}
function formatWorkerError(error) {
if (error?.cause?.code === "ECONNREFUSED") {
return [
@@ -91,17 +101,19 @@ function formatWorkerError(error) {
async function tick() {
if (isRunningTick) return;
isRunningTick = true;
const now = Date.now();
const warningIntervalMs = warningIntervalMinutes * 60_000;
try {
const now = Date.now();
const warningIntervalMs = warningIntervalMinutes * 60_000;
if (now - lastWarningCheckAt >= warningIntervalMs) {
lastWarningCheckAt = now;
await callNotificationEndpoint("/api/notifications/check");
await callNotificationEndpointSafely("/api/notifications/check");
}
const warsawTime = getWarsawDateParts();
if (isAtOrAfterTime(warsawTime.time, morningBriefTime) && lastMorningBriefDate !== warsawTime.dateKey) {
await callNotificationEndpoint("/api/notifications/daily-brief");
const sentBrief = await callNotificationEndpointSafely("/api/notifications/daily-brief");
if (!sentBrief) return;
lastMorningBriefDate = warsawTime.dateKey;
}
} catch (error) {