Merged in feature/redis (pull request #1478)

Distributed cache

* cache deleteKey now uses an options object instead of a lonely argument variable fuzzy

* merge

* remove debug logs and cleanup

* cleanup

* add fault handling

* add fault handling

* add pid when logging redis client creation

* add identifier when logging redis client creation

* cleanup

* feat: add redis-api as it's own app

* feature: use http wrapper for redis

* feat: add the possibility to fallback to unstable_cache

* Add error handling if redis cache is unresponsive

* add logging for unstable_cache

* merge

* don't cache errors

* fix: metadatabase on branchdeploys

* Handle when /en/destinations throws
add ErrorBoundary

* Add sentry-logging when ErrorBoundary catches exception

* Fix error handling for distributed cache

* cleanup code

* Added Application Insights back

* Update generateApiKeys script and remove duplicate

* Merge branch 'feature/redis' of bitbucket.org:scandic-swap/web into feature/redis

* merge


Approved-by: Linus Flood
This commit is contained in:
Joakim Jäderberg
2025-03-14 07:54:21 +00:00
committed by Linus Flood
parent a8304e543e
commit fa63b20ed0
141 changed files with 4404 additions and 1941 deletions
+43 -43
View File
@@ -1,9 +1,8 @@
import { metrics } from "@opentelemetry/api"
import { revalidateTag, unstable_cache } from "next/cache"
import { metrics, trace } from "@opentelemetry/api"
import { env } from "@/env/server"
import { generateServiceTokenTag } from "@/utils/generateTag"
import { getCacheClient } from "@/services/dataCache"
import type { ServiceTokenResponse } from "@/types/tokens"
@@ -12,13 +11,49 @@ const meter = metrics.getMeter("trpc.context.serviceToken")
const fetchServiceTokenCounter = meter.createCounter(
"trpc.context.serviceToken.fetch-new-token"
)
const fetchTempServiceTokenCounter = meter.createCounter(
"trpc.context.serviceToken.fetch-temporary"
)
const fetchServiceTokenFailCounter = meter.createCounter(
"trpc.context.serviceToken.fetch-fail"
)
export async function getServiceToken() {
const tracer = trace.getTracer("getServiceToken")
return await tracer.startActiveSpan("getServiceToken", async () => {
let scopes: string[] = []
if (env.ENABLE_BOOKING_FLOW) {
scopes = ["profile", "hotel", "booking", "package", "availability"]
} else {
scopes = ["profile"]
}
const cacheKey = getServiceTokenCacheKey(scopes)
const cacheClient = await getCacheClient()
const token =
await cacheClient.get<Awaited<ReturnType<typeof getJwt>>>(cacheKey)
console.log("[DEBUG] getServiceToken", typeof token, token)
if (!token || token.expiresAt < Date.now()) {
return await tracer.startActiveSpan("fetch new token", async () => {
const newToken = await getJwt(scopes)
const relativeTime = (newToken.expiresAt - Date.now()) / 1000
await cacheClient.set(cacheKey, newToken, relativeTime)
return newToken.jwt
})
}
return token.jwt
})
}
async function getJwt(scopes: string[]) {
fetchServiceTokenCounter.add(1)
const jwt = await fetchServiceToken(scopes)
const expiresAt = Date.now() + jwt.expires_in * 1000
return { expiresAt, jwt }
}
async function fetchServiceToken(scopes: string[]) {
fetchServiceTokenCounter.add(1)
@@ -69,41 +104,6 @@ async function fetchServiceToken(scopes: string[]) {
return response.json() as Promise<ServiceTokenResponse>
}
export async function getServiceToken() {
let scopes: string[] = []
if (env.ENABLE_BOOKING_FLOW) {
scopes = ["profile", "hotel", "booking", "package", "availability"]
} else {
scopes = ["profile"]
}
const tag = generateServiceTokenTag(scopes)
const getCachedJwt = unstable_cache(
async (scopes) => {
const jwt = await fetchServiceToken(scopes)
const expiresAt = Date.now() + jwt.expires_in * 1000
return { expiresAt, jwt }
},
[tag],
{ tags: [tag] }
)
const cachedJwt = await getCachedJwt(scopes)
if (cachedJwt.expiresAt < Date.now()) {
console.log(
"trpc.context.serviceToken: Service token expired, revalidating tag"
)
revalidateTag(tag)
console.log(
"trpc.context.serviceToken: Fetching new temporary service token."
)
fetchTempServiceTokenCounter.add(1)
const newToken = await fetchServiceToken(scopes)
return newToken
}
return cachedJwt.jwt
function getServiceTokenCacheKey(scopes: string[]): string {
return `serviceToken:${scopes.join(",")}`
}