fix: keep daily brief independent from warning checks
This commit is contained in:
@@ -9,6 +9,7 @@ const ALLOWED_PATHS = new Set([
|
|||||||
"product",
|
"product",
|
||||||
]);
|
]);
|
||||||
const IMGW_BASE_URL = "https://danepubliczne.imgw.pl/api/data";
|
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[] }> }) {
|
export async function GET(_: Request, context: { params: Promise<{ path: string[] }> }) {
|
||||||
const { path } = await context.params;
|
const { path } = await context.params;
|
||||||
@@ -24,7 +25,7 @@ export async function GET(_: Request, context: { params: Promise<{ path: string[
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(`${IMGW_BASE_URL}/${upstreamPath}`, {
|
const response = await fetch(`${IMGW_BASE_URL}/${upstreamPath}`, {
|
||||||
next: { revalidate: 300 },
|
next: { revalidate: 300 },
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json", "User-Agent": USER_AGENT },
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return NextResponse.json({ error: "IMGW API jest chwilowo niedostępne." }, { status: response.status });
|
return NextResponse.json({ error: "IMGW API jest chwilowo niedostępne." }, { status: response.status });
|
||||||
|
|||||||
@@ -2,14 +2,18 @@ import { normalizeWarning } from "@/lib/weather-utils";
|
|||||||
import type { RawWarning, WeatherWarning } from "@/types/imgw";
|
import type { RawWarning, WeatherWarning } from "@/types/imgw";
|
||||||
|
|
||||||
const IMGW_WARNINGS_METEO_URL = "https://danepubliczne.imgw.pl/api/data/warningsmeteo";
|
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[]> {
|
export async function fetchMeteoWarnings(signal?: AbortSignal): Promise<WeatherWarning[]> {
|
||||||
const response = await fetch(IMGW_WARNINGS_METEO_URL, {
|
const response = await fetch(IMGW_WARNINGS_METEO_URL, {
|
||||||
headers: { accept: "application/json" },
|
headers: { accept: "application/json", "user-agent": USER_AGENT },
|
||||||
next: { revalidate: 300 },
|
next: { revalidate: 300 },
|
||||||
signal,
|
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[];
|
const rows = await response.json() as RawWarning[];
|
||||||
return Array.isArray(rows) ? rows.map((warning, index) => normalizeWarning(warning, "meteo", index)) : [];
|
return Array.isArray(rows) ? rows.map((warning, index) => normalizeWarning(warning, "meteo", index)) : [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,16 @@ async function callNotificationEndpoint(path) {
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function callNotificationEndpointSafely(path) {
|
||||||
|
try {
|
||||||
|
await callNotificationEndpoint(path);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(formatWorkerError(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function formatWorkerError(error) {
|
function formatWorkerError(error) {
|
||||||
if (error?.cause?.code === "ECONNREFUSED") {
|
if (error?.cause?.code === "ECONNREFUSED") {
|
||||||
return [
|
return [
|
||||||
@@ -91,17 +101,19 @@ function formatWorkerError(error) {
|
|||||||
async function tick() {
|
async function tick() {
|
||||||
if (isRunningTick) return;
|
if (isRunningTick) return;
|
||||||
isRunningTick = true;
|
isRunningTick = true;
|
||||||
|
const now = Date.now();
|
||||||
|
const warningIntervalMs = warningIntervalMinutes * 60_000;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const now = Date.now();
|
|
||||||
const warningIntervalMs = warningIntervalMinutes * 60_000;
|
|
||||||
if (now - lastWarningCheckAt >= warningIntervalMs) {
|
if (now - lastWarningCheckAt >= warningIntervalMs) {
|
||||||
lastWarningCheckAt = now;
|
lastWarningCheckAt = now;
|
||||||
await callNotificationEndpoint("/api/notifications/check");
|
await callNotificationEndpointSafely("/api/notifications/check");
|
||||||
}
|
}
|
||||||
|
|
||||||
const warsawTime = getWarsawDateParts();
|
const warsawTime = getWarsawDateParts();
|
||||||
if (isAtOrAfterTime(warsawTime.time, morningBriefTime) && lastMorningBriefDate !== warsawTime.dateKey) {
|
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;
|
lastMorningBriefDate = warsawTime.dateKey;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user