fix: improve error handling

- Do not throw in onError callback for server client. This lets the originating error bubble to Next.js.
- Do not log errors inside the service token procedure, server client onError callback will log all procedure errors.
- Log errors for fetching service token failure.
This commit is contained in:
Michael Zetterberg
2024-10-11 10:42:40 +02:00
committed by Pontus Dreij
parent f63cecc488
commit 194ca601b5
3 changed files with 65 additions and 49 deletions

View File

@@ -50,8 +50,6 @@ export function serverClient() {
redirect(redirectUrl) redirect(redirectUrl)
} }
} }
throw internalServerError()
}, },
}) })
} }

View File

@@ -21,6 +21,7 @@ const fetchServiceTokenFailCounter = meter.createCounter(
async function fetchServiceToken(scopes: string[]) { async function fetchServiceToken(scopes: string[]) {
fetchServiceTokenCounter.add(1) fetchServiceTokenCounter.add(1)
const response = await fetch(`${env.CURITY_ISSUER_USER}/oauth/v2/token`, { const response = await fetch(`${env.CURITY_ISSUER_USER}/oauth/v2/token`, {
method: "POST", method: "POST",
headers: { headers: {
@@ -36,21 +37,39 @@ async function fetchServiceToken(scopes: string[]) {
}) })
if (!response.ok) { if (!response.ok) {
fetchServiceTokenFailCounter.add(1, { const text = await response.text()
error_type: "http_error", const error = {
error: JSON.stringify({
status: response.status, status: response.status,
statusText: response.statusText, statusText: response.statusText,
}), text,
})
throw new Error("Failed to obtain service token")
} }
return response.json() fetchServiceTokenFailCounter.add(1, {
error_type: "http_error",
error: JSON.stringify(error),
})
console.error(
"fetchServiceToken error",
JSON.stringify({
query: {
grant_type: "client_credentials",
client_id: env.CURITY_CLIENT_ID_SERVICE,
scope: scopes.join(" "),
},
error,
})
)
throw new Error(
`[fetchServiceToken] Failed to obtain service token: ${JSON.stringify(error)}`
)
}
return response.json() as Promise<ServiceTokenResponse>
} }
export async function getServiceToken(): Promise<ServiceTokenResponse> { export async function getServiceToken() {
try {
const scopes = ["profile", "hotel", "booking"] const scopes = ["profile", "hotel", "booking"]
const tag = generateServiceTokenTag(scopes) const tag = generateServiceTokenTag(scopes)
const getCachedJwt = unstable_cache( const getCachedJwt = unstable_cache(
@@ -69,6 +88,7 @@ export async function getServiceToken(): Promise<ServiceTokenResponse> {
console.log( console.log(
"trpc.context.serviceToken: Service token expired, revalidating tag" "trpc.context.serviceToken: Service token expired, revalidating tag"
) )
revalidateTag(tag) revalidateTag(tag)
console.log( console.log(
@@ -80,8 +100,4 @@ export async function getServiceToken(): Promise<ServiceTokenResponse> {
} }
return cachedJwt.jwt return cachedJwt.jwt
} catch (error) {
console.error("Error fetching service token:", error)
throw error
}
} }

View File

@@ -124,7 +124,7 @@ export const safeProtectedProcedure = t.procedure.use(async function (opts) {
export const serviceProcedure = t.procedure.use(async (opts) => { export const serviceProcedure = t.procedure.use(async (opts) => {
const { access_token } = await getServiceToken() const { access_token } = await getServiceToken()
if (!access_token) { if (!access_token) {
throw internalServerError(`Failed to obtain service token`) throw internalServerError(`[serviceProcedure] No service token`)
} }
return opts.next({ return opts.next({
ctx: { ctx: {
@@ -144,7 +144,9 @@ export const serviceServerActionProcedure = serverActionProcedure.use(
async (opts) => { async (opts) => {
const { access_token } = await getServiceToken() const { access_token } = await getServiceToken()
if (!access_token) { if (!access_token) {
throw internalServerError("Failed to obtain service token") throw internalServerError(
"[serviceServerActionProcedure]: No service token"
)
} }
return opts.next({ return opts.next({
ctx: { ctx: {