Avoid caching failed scan snapshots
This commit is contained in:
+1
-1
@@ -112,7 +112,7 @@ services:
|
|||||||
POLYWEATHER_OBSERVATION_COLLECTOR_INITIAL_DELAY_SEC: ${POLYWEATHER_OBSERVATION_COLLECTOR_INITIAL_DELAY_SEC:-5}
|
POLYWEATHER_OBSERVATION_COLLECTOR_INITIAL_DELAY_SEC: ${POLYWEATHER_OBSERVATION_COLLECTOR_INITIAL_DELAY_SEC:-5}
|
||||||
POLYWEATHER_OBSERVATION_COLLECTOR_MADIS_SEC: ${POLYWEATHER_OBSERVATION_COLLECTOR_MADIS_SEC:-300}
|
POLYWEATHER_OBSERVATION_COLLECTOR_MADIS_SEC: ${POLYWEATHER_OBSERVATION_COLLECTOR_MADIS_SEC:-300}
|
||||||
POLYWEATHER_OBSERVATION_COLLECTOR_TICK_SEC: ${POLYWEATHER_OBSERVATION_COLLECTOR_TICK_SEC:-30}
|
POLYWEATHER_OBSERVATION_COLLECTOR_TICK_SEC: ${POLYWEATHER_OBSERVATION_COLLECTOR_TICK_SEC:-30}
|
||||||
POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: ${POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED:-true}
|
POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: 'true'
|
||||||
POLYWEATHER_SERVICE_ROLE: web
|
POLYWEATHER_SERVICE_ROLE: web
|
||||||
UVICORN_WORKERS: ${UVICORN_WORKERS:-2}
|
UVICORN_WORKERS: ${UVICORN_WORKERS:-2}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { proxyBackendJsonGet } from "@/lib/api-proxy";
|
import { proxyBackendJsonGet } from "@/lib/api-proxy";
|
||||||
import { buildForceRefreshProxyCachePolicy } from "@/lib/proxy-cache-policy";
|
import {
|
||||||
|
buildForceRefreshProxyCachePolicy,
|
||||||
|
buildScanTerminalResponseCacheControl,
|
||||||
|
} from "@/lib/proxy-cache-policy";
|
||||||
import { DASHBOARD_REFRESH_POLICY_SEC } from "@/lib/refresh-policy";
|
import { DASHBOARD_REFRESH_POLICY_SEC } from "@/lib/refresh-policy";
|
||||||
import {
|
import {
|
||||||
createProxyTimer,
|
createProxyTimer,
|
||||||
@@ -64,6 +67,11 @@ export async function GET(req: NextRequest) {
|
|||||||
try {
|
try {
|
||||||
return await proxyBackendJsonGet(req, {
|
return await proxyBackendJsonGet(req, {
|
||||||
cacheControl: cachePolicy.responseCacheControl,
|
cacheControl: cachePolicy.responseCacheControl,
|
||||||
|
cacheControlForData: (data) =>
|
||||||
|
buildScanTerminalResponseCacheControl(
|
||||||
|
data,
|
||||||
|
cachePolicy.responseCacheControl,
|
||||||
|
),
|
||||||
fetchCache:
|
fetchCache:
|
||||||
cachePolicy.fetchMode === "no-store" ? "no-store" : undefined,
|
cachePolicy.fetchMode === "no-store" ? "no-store" : undefined,
|
||||||
publicMessage: "Failed to fetch scan terminal data",
|
publicMessage: "Failed to fetch scan terminal data",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {
|
import {
|
||||||
|
buildScanTerminalResponseCacheControl,
|
||||||
buildCityDetailProxyCachePolicy,
|
buildCityDetailProxyCachePolicy,
|
||||||
buildForceRefreshProxyCachePolicy,
|
buildForceRefreshProxyCachePolicy,
|
||||||
isForceRefreshValue,
|
isForceRefreshValue,
|
||||||
@@ -26,6 +27,24 @@ export function runTests() {
|
|||||||
const scanForced = buildForceRefreshProxyCachePolicy("true", 10);
|
const scanForced = buildForceRefreshProxyCachePolicy("true", 10);
|
||||||
assert.equal(scanForced.fetchMode, "no-store");
|
assert.equal(scanForced.fetchMode, "no-store");
|
||||||
|
|
||||||
|
const normalScanCache = "public, max-age=0, s-maxage=300, stale-while-revalidate=900";
|
||||||
|
assert.equal(
|
||||||
|
buildScanTerminalResponseCacheControl({ status: "ready", stale: false }, normalScanCache),
|
||||||
|
normalScanCache,
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
buildScanTerminalResponseCacheControl({ status: "failed", stale: false }, normalScanCache),
|
||||||
|
"no-store, max-age=0",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
buildScanTerminalResponseCacheControl({ status: "partial", stale: false }, normalScanCache),
|
||||||
|
"no-store, max-age=0",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
buildScanTerminalResponseCacheControl({ status: "ready", stale: true }, normalScanCache),
|
||||||
|
"no-store, max-age=0",
|
||||||
|
);
|
||||||
|
|
||||||
const scanTerminalProxySource = fs.readFileSync(
|
const scanTerminalProxySource = fs.readFileSync(
|
||||||
path.join(process.cwd(), "app", "api", "scan", "terminal", "route.ts"),
|
path.join(process.cwd(), "app", "api", "scan", "terminal", "route.ts"),
|
||||||
"utf8",
|
"utf8",
|
||||||
@@ -40,6 +59,11 @@ export function runTests() {
|
|||||||
/buildForceRefreshProxyCachePolicy\(forceRefresh,\s*10\)/,
|
/buildForceRefreshProxyCachePolicy\(forceRefresh,\s*10\)/,
|
||||||
"scan terminal proxy must not use the old 10 second edge cache because it over-drives the slow scan endpoint",
|
"scan terminal proxy must not use the old 10 second edge cache because it over-drives the slow scan endpoint",
|
||||||
);
|
);
|
||||||
|
assert.match(
|
||||||
|
scanTerminalProxySource,
|
||||||
|
/cacheControlForData:\s*\(data\)\s*=>\s*buildScanTerminalResponseCacheControl/,
|
||||||
|
"scan terminal proxy must not CDN-cache failed, stale, or partial business payloads",
|
||||||
|
);
|
||||||
|
|
||||||
const scanTerminalClientSource = fs.readFileSync(
|
const scanTerminalClientSource = fs.readFileSync(
|
||||||
path.join(
|
path.join(
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ export type ProxyCachePolicy = {
|
|||||||
revalidateSeconds?: number;
|
revalidateSeconds?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NO_STORE_CACHE_CONTROL = "no-store, max-age=0";
|
||||||
|
|
||||||
export function isForceRefreshValue(value: string | null | undefined) {
|
export function isForceRefreshValue(value: string | null | undefined) {
|
||||||
return String(value || "").trim().toLowerCase() === "true";
|
return String(value || "").trim().toLowerCase() === "true";
|
||||||
}
|
}
|
||||||
@@ -15,7 +17,7 @@ export function buildForceRefreshProxyCachePolicy(
|
|||||||
if (isForceRefreshValue(forceRefresh)) {
|
if (isForceRefreshValue(forceRefresh)) {
|
||||||
return {
|
return {
|
||||||
fetchMode: "no-store",
|
fetchMode: "no-store",
|
||||||
responseCacheControl: "no-store, max-age=0",
|
responseCacheControl: NO_STORE_CACHE_CONTROL,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -35,7 +37,7 @@ export function buildCityDetailProxyCachePolicy(
|
|||||||
if (isForceRefreshValue(forceRefresh)) {
|
if (isForceRefreshValue(forceRefresh)) {
|
||||||
return {
|
return {
|
||||||
fetchMode: "no-store",
|
fetchMode: "no-store",
|
||||||
responseCacheControl: "no-store, max-age=0",
|
responseCacheControl: NO_STORE_CACHE_CONTROL,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -47,3 +49,18 @@ export function buildCityDetailProxyCachePolicy(
|
|||||||
revalidateSeconds,
|
revalidateSeconds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildScanTerminalResponseCacheControl(
|
||||||
|
data: unknown,
|
||||||
|
readyCacheControl: string,
|
||||||
|
) {
|
||||||
|
if (!data || typeof data !== "object") {
|
||||||
|
return NO_STORE_CACHE_CONTROL;
|
||||||
|
}
|
||||||
|
const payload = data as { stale?: unknown; status?: unknown };
|
||||||
|
const status = String(payload.status || "").trim().toLowerCase();
|
||||||
|
if (payload.stale === true || (status && status !== "ready")) {
|
||||||
|
return NO_STORE_CACHE_CONTROL;
|
||||||
|
}
|
||||||
|
return readyCacheControl;
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,11 +91,7 @@ def test_docker_compose_isolates_collector_from_web_and_bot_services():
|
|||||||
assert "POLYWEATHER_SERVICE_ROLE: bot" in compose
|
assert "POLYWEATHER_SERVICE_ROLE: bot" in compose
|
||||||
assert "POLYWEATHER_SERVICE_ROLE: collector" in collector_block
|
assert "POLYWEATHER_SERVICE_ROLE: collector" in collector_block
|
||||||
assert "POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: 'false'" in bot_block
|
assert "POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: 'false'" in bot_block
|
||||||
assert (
|
assert "POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: 'true'" in web_block
|
||||||
"POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: "
|
|
||||||
"${POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED:-true}"
|
|
||||||
in web_block
|
|
||||||
)
|
|
||||||
assert "POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: 'false'" in collector_block
|
assert "POLYWEATHER_SCAN_TERMINAL_PREWARM_ENABLED: 'false'" in collector_block
|
||||||
assert "POLYWEATHER_OBSERVATION_COLLECTOR_ENABLED: 'false'" in bot_block
|
assert "POLYWEATHER_OBSERVATION_COLLECTOR_ENABLED: 'false'" in bot_block
|
||||||
assert "POLYWEATHER_OBSERVATION_COLLECTOR_ENABLED: 'false'" in web_block
|
assert "POLYWEATHER_OBSERVATION_COLLECTOR_ENABLED: 'false'" in web_block
|
||||||
|
|||||||
Reference in New Issue
Block a user