Merged in fix/warmup-not-throwing (pull request #3179)
fix: warmup threw error * fix: warmup threw error * . Approved-by: Linus Flood
This commit is contained in:
@@ -16,6 +16,7 @@ export async function GET(req: NextRequest) {
|
||||
const key = url.searchParams.get("key")
|
||||
|
||||
if (!isAuthroized(req)) {
|
||||
logger.error("Unauthorized warmup request")
|
||||
return unauthorizedResponse()
|
||||
}
|
||||
|
||||
@@ -25,7 +26,7 @@ export async function GET(req: NextRequest) {
|
||||
return invalidKeyResponse(key)
|
||||
}
|
||||
|
||||
logger.debug("Warming up:", key)
|
||||
logger.info("Warming up:", key)
|
||||
const warmupResult = await warmup(key)
|
||||
const executionTime = performance.now() - executionStart
|
||||
|
||||
@@ -61,7 +62,7 @@ function warmupCompletedResponse(
|
||||
key: string,
|
||||
executionTime: number
|
||||
) {
|
||||
logger.debug(`Warmup completed: ${key} in ${executionTime.toFixed(2)}ms`)
|
||||
logger.info(`Warmup completed: ${key} in ${executionTime.toFixed(2)}ms`)
|
||||
return NextResponse.json(
|
||||
{
|
||||
...warmupResult,
|
||||
@@ -77,7 +78,7 @@ function warmupSkippedResponse(
|
||||
key: string,
|
||||
executionTime: number
|
||||
) {
|
||||
logger.debug("Warmup skipped:", key)
|
||||
logger.info("Warmup skipped:", key)
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
|
||||
@@ -1,19 +1,50 @@
|
||||
import crypto from "crypto"
|
||||
import crypto from "node:crypto"
|
||||
|
||||
import Sentry from "@sentry/nextjs"
|
||||
import jwt from "jsonwebtoken"
|
||||
|
||||
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
||||
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
||||
import { type WarmupFunctionsKey } from "@/services/warmup/warmupKeys"
|
||||
|
||||
import {
|
||||
type WarmupFunctionsKey,
|
||||
warmupKeys,
|
||||
} from "@/services/warmup/warmupKeys"
|
||||
import { timeout } from "@/utils/timeout"
|
||||
import { configureSentry } from "../utils/initSentry"
|
||||
import { safeTry } from "../utils/safeTry"
|
||||
|
||||
import type { Config, Context } from "@netlify/functions"
|
||||
|
||||
async function WarmupHandler(request: Request, context: Context) {
|
||||
const warmupLogger = createLogger("warmup")
|
||||
await configureSentry()
|
||||
|
||||
export const config: Config = {
|
||||
method: "POST",
|
||||
}
|
||||
const warmupLogger = {
|
||||
info: (message: string, ...args: unknown[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`[WARMUP] ${message}`, ...args)
|
||||
Sentry.logger.info(`[WARMUP] ${message}`, { ...args })
|
||||
},
|
||||
warn: (message: string, ...args: unknown[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`[WARMUP] ${message}`, ...args)
|
||||
Sentry.logger.warn(`[WARMUP] ${message}`, { ...args })
|
||||
},
|
||||
error: (message: string, ...args: unknown[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`[WARMUP] ${message}`, ...args)
|
||||
Sentry.logger.error(`[WARMUP] ${message}`, { ...args })
|
||||
},
|
||||
}
|
||||
|
||||
const langs = ["en", "sv", "no", "fi", "da", "de"] as const
|
||||
export const warmupKeys = [
|
||||
...langs.map((lang) => `countries_${lang}` as const),
|
||||
"hotelsByCountry",
|
||||
...langs.map((lang) => `hotelData_${lang}` as const),
|
||||
...langs.map((lang) => `autoComplete_${lang}` as const),
|
||||
] satisfies WarmupFunctionsKey[]
|
||||
|
||||
export default async function WarmupHandler(
|
||||
request: Request,
|
||||
context: Context
|
||||
) {
|
||||
const [_, error] = await safeTry(validateRequest(request, context))
|
||||
|
||||
if (error) {
|
||||
@@ -42,13 +73,11 @@ async function validateRequest(
|
||||
request: Request,
|
||||
context: Context
|
||||
): Promise<true> {
|
||||
const warmupLogger = createLogger("warmup")
|
||||
if (request.method !== "POST") {
|
||||
throw new Error(ErrorCodes.METHOD_NOT_ALLOWED)
|
||||
}
|
||||
|
||||
const warmupEnabled =
|
||||
true ||
|
||||
process.env.WARMUP_ENABLED === "true" ||
|
||||
Netlify.env.get("WARMUP_ENABLED") === "true"
|
||||
|
||||
@@ -61,7 +90,6 @@ async function validateRequest(
|
||||
}
|
||||
|
||||
const body = await request.text()
|
||||
warmupLogger.info("Warmup body", body)
|
||||
const deployment = JSON.parse(body) as DeploymentInfo
|
||||
if (!deployment) {
|
||||
throw new Error(ErrorCodes.UNABLE_TO_PARSE_DEPLOYMENT_INFO)
|
||||
@@ -76,7 +104,6 @@ async function validateRequest(
|
||||
throw new Error(ErrorCodes.REQUEST_NOT_FOR_CURRENT_CONTEXT)
|
||||
}
|
||||
|
||||
warmupLogger.info("Warmup request", deployment)
|
||||
let signature: string
|
||||
try {
|
||||
const headerValue = request.headers.get("x-webhook-signature")
|
||||
@@ -103,7 +130,6 @@ async function validateRequest(
|
||||
}
|
||||
|
||||
export async function performWarmup(context: Context) {
|
||||
const warmupLogger = createLogger("warmup")
|
||||
for (const key of warmupKeys) {
|
||||
warmupLogger.info("Warming up cache", key)
|
||||
await callWarmup(key, context)
|
||||
@@ -112,16 +138,12 @@ export async function performWarmup(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
async function callWarmup(key: WarmupFunctionsKey, context: Context) {
|
||||
const warmupLogger = createLogger("warmup")
|
||||
async function callWarmup(key: (typeof warmupKeys)[number], context: Context) {
|
||||
const baseUrl = context.url.origin
|
||||
|
||||
const url = new URL("/api/web/warmup", baseUrl)
|
||||
url.searchParams.set("key", key)
|
||||
|
||||
const warmupToken =
|
||||
process.env.WARMUP_TOKEN || Netlify.env.get("WARMUP_TOKEN")
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
@@ -130,7 +152,6 @@ async function callWarmup(key: WarmupFunctionsKey, context: Context) {
|
||||
},
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
warmupLogger.error(
|
||||
`Warmup failed '${url.href}' with error: ${response.status}: ${response.statusText}`
|
||||
@@ -143,13 +164,7 @@ async function callWarmup(key: WarmupFunctionsKey, context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
export default WarmupHandler
|
||||
export const config: Config = {
|
||||
method: "POST",
|
||||
}
|
||||
|
||||
async function validateSignature(token: string, buffer: string) {
|
||||
const warmupLogger = createLogger("warmup")
|
||||
try {
|
||||
const secret =
|
||||
process.env.WARMUP_SIGNATURE_SECRET ||
|
||||
@@ -218,14 +233,14 @@ type DeploymentInfo = {
|
||||
updated_at: string
|
||||
user_id: string
|
||||
error_message: string | null
|
||||
required: any[]
|
||||
required_functions: any[]
|
||||
required: unknown[]
|
||||
required_functions: unknown[]
|
||||
commit_ref: string
|
||||
review_id: string | null
|
||||
branch: string
|
||||
commit_url: string
|
||||
skipped: any
|
||||
locked: any
|
||||
skipped: unknown
|
||||
locked: unknown
|
||||
title: string
|
||||
commit_message: string | null
|
||||
review_url: string | null
|
||||
@@ -235,10 +250,10 @@ type DeploymentInfo = {
|
||||
available_functions: unknown[]
|
||||
screenshot_url: string | null
|
||||
committer: string
|
||||
skipped_log: any
|
||||
skipped_log: unknown
|
||||
manual_deploy: boolean
|
||||
plugin_state: string
|
||||
lighthouse_plugin_scores: any
|
||||
lighthouse_plugin_scores: unknown
|
||||
links: {
|
||||
permalink: string
|
||||
alias: string
|
||||
@@ -253,7 +268,7 @@ type DeploymentInfo = {
|
||||
}[]
|
||||
public_repo: boolean
|
||||
pending_review_reason: string | null
|
||||
lighthouse: any
|
||||
lighthouse: unknown
|
||||
edge_functions_present: boolean
|
||||
expires_at: string | null
|
||||
blobs_region: string
|
||||
@@ -273,3 +288,7 @@ const ErrorCodes = {
|
||||
WARMUP_DISABLED: "WARMUP IS DISABLED",
|
||||
} as const
|
||||
type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes]
|
||||
|
||||
function timeout(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
export async function warmupHotelDataOnLang(lang: Lang) {
|
||||
const warmupHotelDataOnLangLogger = createLogger("warmupHotelDataOnLang")
|
||||
const PUBLIC_URL = Netlify.env.get("PUBLIC_URL")
|
||||
|
||||
warmupHotelDataOnLangLogger.info(
|
||||
`[WARMUP] Started warmup cache hoteldata for language ${lang} at: ${new Date().toISOString()}!`
|
||||
)
|
||||
|
||||
try {
|
||||
const hotelsResponse = await fetch(
|
||||
`${PUBLIC_URL}/api/hoteldata?lang=${lang}`,
|
||||
{
|
||||
headers: { cache: "no-store" },
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
}
|
||||
)
|
||||
|
||||
if (!hotelsResponse.ok) {
|
||||
throw new Error(
|
||||
`[WARMUP] Failed to warmup cache for hotels on language ${lang} with error: ${hotelsResponse.statusText}`
|
||||
)
|
||||
}
|
||||
|
||||
const hotels = await hotelsResponse.json()
|
||||
warmupHotelDataOnLangLogger.info(
|
||||
`[WARMUP] Retrieved ${hotels.length} hotels.`
|
||||
)
|
||||
} catch (error) {
|
||||
warmupHotelDataOnLangLogger.error(
|
||||
`[WARMUP] Error warming cache with hoteldata on language ${lang} with error: ${error}`
|
||||
)
|
||||
}
|
||||
}
|
||||
21
apps/scandic-web/netlify/utils/initSentry.ts
Normal file
21
apps/scandic-web/netlify/utils/initSentry.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import Sentry from "@sentry/nextjs"
|
||||
|
||||
export const denyUrls: (string | RegExp)[] = [
|
||||
// Ignore preview urls
|
||||
/\/.{2}\/preview\//,
|
||||
]
|
||||
|
||||
export const onRequestError = Sentry.captureRequestError
|
||||
|
||||
export async function configureSentry() {
|
||||
const sentryEnvironment = Netlify.env.get("SENTRY_ENVIRONMENT")
|
||||
const sampleRate = Number(Netlify.env.get("SENTRY_SERVER_SAMPLERATE") ?? 0.01)
|
||||
Sentry.init({
|
||||
dsn: "https://fe39c070b4154e2f9cc35f0e5de0aedb@o4508102497206272.ingest.de.sentry.io/4508102500286544",
|
||||
environment: sentryEnvironment,
|
||||
enabled: sentryEnvironment !== "development",
|
||||
tracesSampleRate: sampleRate,
|
||||
denyUrls: denyUrls,
|
||||
enableLogs: true,
|
||||
})
|
||||
}
|
||||
11
apps/scandic-web/netlify/utils/safeTry.ts
Normal file
11
apps/scandic-web/netlify/utils/safeTry.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type SafeTryResult<T> = Promise<
|
||||
[T, undefined] | [undefined, Error | unknown]
|
||||
>
|
||||
|
||||
export async function safeTry<T>(func: Promise<T>): SafeTryResult<T> {
|
||||
try {
|
||||
return [await func, undefined] as const
|
||||
} catch (err) {
|
||||
return [undefined, err instanceof Error ? err : (err as unknown)] as const
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user