mirror of
https://github.com/Nezumi-2711/uptime-monitoring.git
synced 2026-09-22 13:48:31 +00:00
fix: optimize pricing for deploying
This commit is contained in:
@@ -40,13 +40,13 @@ export type PublicStatus = {
|
||||
};
|
||||
|
||||
export function getStatus(signal?: AbortSignal) {
|
||||
return getJson<PublicStatus>('/api/status', { signal });
|
||||
return getJson<PublicStatus>('/api/status', { signal, cache: 'no-store' });
|
||||
}
|
||||
|
||||
export function getIncidentHistory(signal?: AbortSignal) {
|
||||
return getJson<{ incidents: PublicIncident[] }>('/api/status/incidents', { signal });
|
||||
return getJson<{ incidents: PublicIncident[] }>('/api/status/incidents', { signal, cache: 'no-store' });
|
||||
}
|
||||
|
||||
export function getPublicIncident(id: number, signal?: AbortSignal) {
|
||||
return getJson<{ incident: PublicIncident }>(`/api/status/incidents/${id}`, { signal });
|
||||
return getJson<{ incident: PublicIncident }>(`/api/status/incidents/${id}`, { signal, cache: 'no-store' });
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export function useStatusQuery() {
|
||||
queryKey: statusKeys.all,
|
||||
queryFn: ({ signal }) => getStatus(signal),
|
||||
refetchInterval: 60_000,
|
||||
refetchIntervalInBackground: true,
|
||||
refetchIntervalInBackground: false,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
@@ -21,8 +21,9 @@ export function useIncidentHistoryQuery() {
|
||||
return useQuery({
|
||||
queryKey: statusKeys.history,
|
||||
queryFn: ({ signal }) => getIncidentHistory(signal),
|
||||
refetchInterval: 120_000,
|
||||
refetchInterval: 300_000,
|
||||
refetchIntervalInBackground: false,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@ import { resolveFavicon } from './monitors';
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
const FAVICON_CACHE_SECONDS = 86_400;
|
||||
const STATUS_CACHE_TIME_HEADER = 'X-Upwatch-Status-Cache-Time';
|
||||
const STATUS_NO_STORE_HEADERS = {
|
||||
'Cache-Control': 'no-store',
|
||||
'CDN-Cache-Control': 'no-store',
|
||||
'Cloudflare-CDN-Cache-Control': 'no-store',
|
||||
};
|
||||
type ServiceStatus = 'up' | 'degraded' | 'down' | 'unknown' | 'maintenance';
|
||||
type OverallStatus = 'operational' | 'degraded' | 'down';
|
||||
type DailyAggregate = { monitorId: number; day: Date; totalChecks: number; upChecks: number };
|
||||
@@ -143,7 +148,7 @@ async function cachedStatusResponse(context: Context<{ Bindings: Env }>): Promis
|
||||
const cached = await cache.match(statusCacheKey(context));
|
||||
if (!cached) return undefined;
|
||||
if (!isStatusCacheFresh(cached, maxAgeSeconds)) return undefined;
|
||||
return cached;
|
||||
return statusResponse(cached);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
@@ -154,10 +159,21 @@ export function isStatusCacheFresh(response: Response, maxAgeSeconds: number, no
|
||||
return Number.isFinite(cachedAt) && now - cachedAt < maxAgeSeconds * 1_000;
|
||||
}
|
||||
|
||||
function statusResponse(response: Response): Response {
|
||||
const headers = new Headers(response.headers);
|
||||
for (const [name, value] of Object.entries(STATUS_NO_STORE_HEADERS)) headers.set(name, value);
|
||||
headers.delete(STATUS_CACHE_TIME_HEADER);
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
function jsonWithEdgeCache(context: Context<{ Bindings: Env }>, body: unknown): Response {
|
||||
const seconds = resolveStatusCacheSeconds(context.env);
|
||||
if (seconds <= 0) return Response.json(body);
|
||||
const response = Response.json(body, {
|
||||
if (seconds <= 0) return Response.json(body, { headers: STATUS_NO_STORE_HEADERS });
|
||||
const cachedResponse = Response.json(body, {
|
||||
headers: {
|
||||
'Cache-Control': `public, max-age=${seconds}`,
|
||||
[STATUS_CACHE_TIME_HEADER]: String(Date.now()),
|
||||
@@ -166,12 +182,12 @@ function jsonWithEdgeCache(context: Context<{ Bindings: Env }>, body: unknown):
|
||||
const cache = edgeCache();
|
||||
if (cache) {
|
||||
try {
|
||||
context.executionCtx.waitUntil(cache.put(statusCacheKey(context), response.clone()).catch(() => undefined));
|
||||
context.executionCtx.waitUntil(cache.put(statusCacheKey(context), cachedResponse).catch(() => undefined));
|
||||
} catch {
|
||||
// No ExecutionContext available (e.g. unit tests): serve without populating the edge cache.
|
||||
}
|
||||
}
|
||||
return response;
|
||||
return Response.json(body, { headers: STATUS_NO_STORE_HEADERS });
|
||||
}
|
||||
|
||||
const statusRoutes = new Hono<{ Bindings: Env }>();
|
||||
|
||||
@@ -119,6 +119,10 @@ describe('public status API', () => {
|
||||
const body = await response.json<PublicStatusResponse>();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get('Cache-Control')).toBe('no-store');
|
||||
expect(response.headers.get('CDN-Cache-Control')).toBe('no-store');
|
||||
expect(response.headers.get('Cloudflare-CDN-Cache-Control')).toBe('no-store');
|
||||
expect(response.headers.get('X-Upwatch-Status-Cache-Time')).toBeNull();
|
||||
expect(body.overall).toBe('operational');
|
||||
expect(body.updatedAt).toEqual(expect.any(Number));
|
||||
expect(body.services).toHaveLength(1);
|
||||
|
||||
Reference in New Issue
Block a user