140 lines
3.1 KiB
TypeScript
140 lines
3.1 KiB
TypeScript
import { type NextRequest, NextResponse } from "next/server"
|
|
|
|
import { env } from "@/env/server"
|
|
|
|
import { warmup } from "@/services/warmup"
|
|
import { isWarmupKey } from "@/services/warmup/warmupKeys"
|
|
import { createLogger } from "@/utils/logger"
|
|
|
|
export const dynamic = "force-dynamic"
|
|
|
|
const logger = createLogger("Warmup")
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const url = new URL(req.url)
|
|
const key = url.searchParams.get("key")
|
|
|
|
if (!isAuthroized(req)) {
|
|
return unauthorizedResponse()
|
|
}
|
|
|
|
const executionStart = performance.now()
|
|
|
|
if (!isWarmupKey(key)) {
|
|
return invalidKeyResponse(key)
|
|
}
|
|
|
|
logger.debug("Warming up:", key)
|
|
const warmupResult = await warmup(key)
|
|
const executionTime = performance.now() - executionStart
|
|
|
|
switch (warmupResult.status) {
|
|
case "completed":
|
|
return warmupCompletedResponse(warmupResult, key, executionTime)
|
|
case "error":
|
|
return warmupErrorResponse(warmupResult, key, executionTime)
|
|
case "skipped":
|
|
return warmupSkippedResponse(warmupResult, key, executionTime)
|
|
default:
|
|
const status = (warmupResult as unknown as { status: string }).status
|
|
throw new Error(`Unknown warmup status '${status}'`)
|
|
}
|
|
}
|
|
|
|
function isAuthroized(req: NextRequest) {
|
|
const authHeader = req.headers.get("Authorization")
|
|
if (!authHeader || !env.WARMUP_TOKEN) {
|
|
return false
|
|
}
|
|
|
|
const token = authHeader.split(" ")[1]
|
|
if (!token) {
|
|
return false
|
|
}
|
|
|
|
return token === env.WARMUP_TOKEN
|
|
}
|
|
|
|
function warmupCompletedResponse(
|
|
warmupResult: Awaited<ReturnType<typeof warmup>>,
|
|
key: string,
|
|
executionTime: number
|
|
) {
|
|
logger.debug(`Warmup completed: ${key} in ${executionTime.toFixed(2)}ms`)
|
|
return NextResponse.json(
|
|
{
|
|
...warmupResult,
|
|
key,
|
|
executionTime: `${executionTime.toFixed(2)}ms`,
|
|
},
|
|
{ status: 200 }
|
|
)
|
|
}
|
|
|
|
function warmupSkippedResponse(
|
|
warmupResult: Awaited<ReturnType<typeof warmup>>,
|
|
key: string,
|
|
executionTime: number
|
|
) {
|
|
logger.debug("Warmup skipped:", key)
|
|
|
|
return NextResponse.json(
|
|
{
|
|
key,
|
|
status: warmupResult.status,
|
|
executionTime: `${executionTime.toFixed(2)}ms`,
|
|
},
|
|
{ status: 200 }
|
|
)
|
|
}
|
|
|
|
function warmupErrorResponse(
|
|
warmupResult: Awaited<ReturnType<typeof warmup>>,
|
|
key: string,
|
|
executionTime: number
|
|
) {
|
|
if (warmupResult.status !== "error") {
|
|
throw new Error("Warmup result is not an error")
|
|
}
|
|
|
|
logger.error("Warmup error", {
|
|
key,
|
|
error: warmupResult.error.message,
|
|
})
|
|
|
|
return NextResponse.json(
|
|
{
|
|
key,
|
|
status: warmupResult.status,
|
|
error: warmupResult.error.message,
|
|
executionTime: `${executionTime.toFixed(2)}ms`,
|
|
},
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
|
|
function unauthorizedResponse() {
|
|
return NextResponse.json(
|
|
{
|
|
error: "Unauthorized access",
|
|
},
|
|
{ status: 401 }
|
|
)
|
|
}
|
|
|
|
function invalidKeyResponse(key: string | null) {
|
|
if (isWarmupKey(key)) {
|
|
throw new Error("Invalid invocation with valid cache key")
|
|
}
|
|
|
|
logger.error(`Invalid key ${key}`)
|
|
|
|
return NextResponse.json(
|
|
{
|
|
key,
|
|
error: `Invalid warmup key: '${key}'`,
|
|
},
|
|
{ status: 400 }
|
|
)
|
|
}
|