Merged in fix/cache-service-token (pull request #1571)

fix(servicetoken): cache it when using unstable_cache

* fix(servicetoken): cache it when using unstable_cache

* Refactor and using cacheOrGet as get/set

* Refactor

* Use expiresAt from cached token


Approved-by: Anton Gunnarsson
This commit is contained in:
Linus Flood
2025-03-19 09:16:11 +00:00
parent 8d1e9954d4
commit dd3fed9423
3 changed files with 34 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
import { metrics, trace } from "@opentelemetry/api" import { metrics, trace, type Tracer } from "@opentelemetry/api"
import { env } from "@/env/server" import { env } from "@/env/server"
@@ -20,32 +20,47 @@ export async function getServiceToken() {
const tracer = trace.getTracer("getServiceToken") const tracer = trace.getTracer("getServiceToken")
return await tracer.startActiveSpan("getServiceToken", async () => { return await tracer.startActiveSpan("getServiceToken", async () => {
let scopes: string[] = [] const scopes = env.ENABLE_BOOKING_FLOW
if (env.ENABLE_BOOKING_FLOW) { ? ["profile", "hotel", "booking", "package", "availability"]
scopes = ["profile", "hotel", "booking", "package", "availability"] : ["profile"]
} else {
scopes = ["profile"]
}
const cacheKey = getServiceTokenCacheKey(scopes) const cacheKey = getServiceTokenCacheKey(scopes)
const cacheClient = await getCacheClient() const cacheClient = await getCacheClient()
const token = const token = await getOrSetServiceTokenFromCache(cacheKey, scopes, tracer)
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 if (token.expiresAt < Date.now()) {
}) await cacheClient.deleteKey(cacheKey)
const newToken = await getOrSetServiceTokenFromCache(
cacheKey,
scopes,
tracer
)
return newToken.jwt
} }
return token.jwt return token.jwt
}) })
} }
async function getOrSetServiceTokenFromCache(
cacheKey: string,
scopes: string[],
tracer: Tracer
) {
const cacheClient = await getCacheClient()
const token = await cacheClient.cacheOrGet(
cacheKey,
async () => {
return await tracer.startActiveSpan("fetch new token", async () => {
const newToken = await getJwt(scopes)
return newToken
})
},
"1h"
)
return token
}
async function getJwt(scopes: string[]) { async function getJwt(scopes: string[]) {
fetchServiceTokenCounter.add(1) fetchServiceTokenCounter.add(1)
const jwt = await fetchServiceToken(scopes) const jwt = await fetchServiceToken(scopes)

View File

@@ -139,7 +139,6 @@ export const safeProtectedProcedure = baseProcedure.use(async function (opts) {
export const serviceProcedure = baseProcedure.use(async (opts) => { export const serviceProcedure = baseProcedure.use(async (opts) => {
const token = await getServiceToken() const token = await getServiceToken()
console.log("[DEBUG] token", typeof token, token)
const { access_token } = token const { access_token } = token
if (!access_token) { if (!access_token) {
throw internalServerError(`[serviceProcedure] No service token`) throw internalServerError(`[serviceProcedure] No service token`)

View File

@@ -10,7 +10,7 @@ import { cacheLogger } from "../../logger"
export const cacheOrGet: DataCache["cacheOrGet"] = async <T>( export const cacheOrGet: DataCache["cacheOrGet"] = async <T>(
key: string | string[], key: string | string[],
callback: (overrideTTL?: (cacheTime: CacheTime) => void) => Promise<T>, callback: () => Promise<T>,
ttl: CacheTime ttl: CacheTime
): Promise<T> => { ): Promise<T> => {
if (!Array.isArray(key)) { if (!Array.isArray(key)) {