Merged in fix/reward-remove-cache (pull request #1542)

fix(reward): remove cache from profile service

* fix(reward): remove cache from profile service


Approved-by: Anton Gunnarsson
This commit is contained in:
Linus Flood
2025-03-14 14:38:38 +00:00
parent f7e100d45c
commit f17406d34f

View File

@@ -10,8 +10,6 @@ import {
} from "@/server/trpc" } from "@/server/trpc"
import { langInput } from "@/server/utils" import { langInput } from "@/server/utils"
import { getCacheClient } from "@/services/dataCache"
import { getAllLoyaltyLevels, getLoyaltyLevel } from "../loyaltyLevel/query" import { getAllLoyaltyLevels, getLoyaltyLevel } from "../loyaltyLevel/query"
import { import {
rewardsAllInput, rewardsAllInput,
@@ -174,139 +172,129 @@ export const rewardQueryRouter = router({
? api.endpoints.v1.Profile.Reward.reward ? api.endpoints.v1.Profile.Reward.reward
: api.endpoints.v1.Profile.reward : api.endpoints.v1.Profile.reward
const cacheClient = await getCacheClient() const apiResponse = await api.get(endpoint, {
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
})
return cacheClient.cacheOrGet( if (!apiResponse.ok) {
endpoint, const text = await apiResponse.text()
async () => { getCurrentRewardFailCounter.add(1, {
const apiResponse = await api.get(endpoint, { error_type: "http_error",
headers: { error: JSON.stringify({
Authorization: `Bearer ${ctx.session.token.access_token}`, status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}),
})
console.error(
"api.reward error ",
JSON.stringify({
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}, },
}) })
)
return null
}
if (!apiResponse.ok) { const data = await apiResponse.json()
const text = await apiResponse.text()
getCurrentRewardFailCounter.add(1, {
error_type: "http_error",
error: JSON.stringify({
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}),
})
console.error(
"api.reward error ",
JSON.stringify({
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
},
})
)
return null
}
const data = await apiResponse.json() const validatedApiRewards = isNewEndpoint
? validateCategorizedRewardsSchema.safeParse(data)
: validateApiRewardSchema.safeParse(data)
const validatedApiRewards = isNewEndpoint if (!validatedApiRewards.success) {
? validateCategorizedRewardsSchema.safeParse(data) getCurrentRewardFailCounter.add(1, {
: validateApiRewardSchema.safeParse(data) locale: ctx.lang,
error_type: "validation_error",
error: JSON.stringify(validatedApiRewards.error),
})
console.error(validatedApiRewards.error)
console.error(
"contentstack.rewards validation error",
JSON.stringify({
query: { locale: ctx.lang },
error: validatedApiRewards.error,
})
)
return null
}
if (!validatedApiRewards.success) { const rewardIds = getNonRedeemedRewardIds(validatedApiRewards.data)
getCurrentRewardFailCounter.add(1, {
locale: ctx.lang,
error_type: "validation_error",
error: JSON.stringify(validatedApiRewards.error),
})
console.error(validatedApiRewards.error)
console.error(
"contentstack.rewards validation error",
JSON.stringify({
query: { locale: ctx.lang },
error: validatedApiRewards.error,
})
)
return null
}
const rewardIds = getNonRedeemedRewardIds(validatedApiRewards.data) const cmsRewards = await getCmsRewards(ctx.lang, rewardIds)
const cmsRewards = await getCmsRewards(ctx.lang, rewardIds) if (!cmsRewards) {
return null
}
if (!cmsRewards) { const wrappedSurprisesIds = validatedApiRewards.data
return null .filter(
} (reward) =>
reward.type === "coupon" &&
reward.rewardType === "Surprise" &&
"coupon" in reward &&
reward.coupon.some(({ unwrapped }) => !unwrapped)
)
.map(({ rewardId }) => rewardId)
const wrappedSurprisesIds = validatedApiRewards.data const rewards = cmsRewards
.filter( .filter(
(reward) => (cmsReward) => !wrappedSurprisesIds.includes(cmsReward.reward_id)
reward.type === "coupon" && )
reward.rewardType === "Surprise" && .map((cmsReward) => {
"coupon" in reward && const apiReward = validatedApiRewards.data.find(
reward.coupon.some(({ unwrapped }) => !unwrapped) ({ rewardId }) => rewardId === cmsReward.reward_id
) )
.map(({ rewardId }) => rewardId)
const rewards = cmsRewards const redeemableCoupons =
.filter( (apiReward &&
(cmsReward) => !wrappedSurprisesIds.includes(cmsReward.reward_id) "coupon" in apiReward &&
) apiReward.coupon.filter(
.map((cmsReward) => { (coupon) => coupon.state !== "redeemed" && coupon.unwrapped
const apiReward = validatedApiRewards.data.find( )) ||
({ rewardId }) => rewardId === cmsReward.reward_id []
)
const redeemableCoupons = const firstRedeemableCouponToExpire = redeemableCoupons.reduce(
(apiReward && (earliest, coupon) => {
"coupon" in apiReward && if (dt(coupon.expiresAt).isBefore(dt(earliest.expiresAt))) {
apiReward.coupon.filter( return coupon
(coupon) => coupon.state !== "redeemed" && coupon.unwrapped
)) ||
[]
const firstRedeemableCouponToExpire = redeemableCoupons.reduce(
(earliest, coupon) => {
if (dt(coupon.expiresAt).isBefore(dt(earliest.expiresAt))) {
return coupon
}
return earliest
},
redeemableCoupons[0]
)?.couponCode
return {
...cmsReward,
id: apiReward?.id,
rewardType: apiReward?.rewardType,
redeemLocation: apiReward?.redeemLocation,
rewardTierLevel:
apiReward && "rewardTierLevel" in apiReward
? apiReward.rewardTierLevel
: undefined,
operaRewardId:
apiReward && "operaRewardId" in apiReward
? apiReward.operaRewardId
: "",
categories:
apiReward && "categories" in apiReward
? apiReward.categories || []
: [],
couponCode: firstRedeemableCouponToExpire,
coupons:
apiReward && "coupon" in apiReward
? apiReward.coupon || []
: [],
} }
}) return earliest
},
redeemableCoupons[0]
)?.couponCode
getCurrentRewardSuccessCounter.add(1) return {
...cmsReward,
id: apiReward?.id,
rewardType: apiReward?.rewardType,
redeemLocation: apiReward?.redeemLocation,
rewardTierLevel:
apiReward && "rewardTierLevel" in apiReward
? apiReward.rewardTierLevel
: undefined,
operaRewardId:
apiReward && "operaRewardId" in apiReward
? apiReward.operaRewardId
: "",
categories:
apiReward && "categories" in apiReward
? apiReward.categories || []
: [],
couponCode: firstRedeemableCouponToExpire,
coupons:
apiReward && "coupon" in apiReward ? apiReward.coupon || [] : [],
}
})
return { rewards } getCurrentRewardSuccessCounter.add(1)
},
"1h" return { rewards }
)
}), }),
surprises: contentStackBaseWithProtectedProcedure surprises: contentStackBaseWithProtectedProcedure
.input(langInput.optional()) // lang is required for client, but not for server .input(langInput.optional()) // lang is required for client, but not for server
@@ -318,120 +306,113 @@ export const rewardQueryRouter = router({
? api.endpoints.v1.Profile.Reward.reward ? api.endpoints.v1.Profile.Reward.reward
: api.endpoints.v1.Profile.reward : api.endpoints.v1.Profile.reward
const cacheClient = await getCacheClient() const apiResponse = await api.get(endpoint, {
return await cacheClient.cacheOrGet( cache: undefined,
endpoint, headers: {
async () => { Authorization: `Bearer ${ctx.session.token.access_token}`,
const apiResponse = await api.get(endpoint, { },
cache: undefined, })
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`, if (!apiResponse.ok) {
const text = await apiResponse.text()
getCurrentRewardFailCounter.add(1, {
error_type: "http_error",
error: JSON.stringify({
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}),
})
console.error(
"api.reward error ",
JSON.stringify({
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}, },
}) })
)
return null
}
if (!apiResponse.ok) { const data = await apiResponse.json()
const text = await apiResponse.text() const validatedApiRewards = isNewEndpoint
getCurrentRewardFailCounter.add(1, { ? validateCategorizedRewardsSchema.safeParse(data)
error_type: "http_error", : validateApiRewardSchema.safeParse(data)
error: JSON.stringify({
status: apiResponse.status, if (!validatedApiRewards.success) {
statusText: apiResponse.statusText, getCurrentRewardFailCounter.add(1, {
text, locale: ctx.lang,
}), error_type: "validation_error",
}) error: JSON.stringify(validatedApiRewards.error),
console.error( })
"api.reward error ", console.error(validatedApiRewards.error)
JSON.stringify({ console.error(
error: { "contentstack.surprises validation error",
status: apiResponse.status, JSON.stringify({
statusText: apiResponse.statusText, query: { locale: ctx.lang },
text, error: validatedApiRewards.error,
}, })
}) )
) return null
}
const rewardIds = validatedApiRewards.data
.map((reward) => reward?.rewardId)
.filter((rewardId): rewardId is string => !!rewardId)
.sort()
const cmsRewards = await getCmsRewards(ctx.lang, rewardIds)
if (!cmsRewards) {
return null
}
getCurrentRewardSuccessCounter.add(1)
const surprises: Surprise[] = validatedApiRewards.data
// TODO: Add predicates once legacy endpoints are removed
.filter((reward) => {
if (reward?.rewardType !== "Surprise") {
return false
}
if (!("coupon" in reward)) {
return false
}
const unwrappedCoupons =
reward.coupon.filter((coupon) => !coupon.unwrapped) || []
if (unwrappedCoupons.length === 0) {
return false
}
return true
})
.map((surprise) => {
const reward = cmsRewards.find(
({ reward_id }) => surprise.rewardId === reward_id
)
if (!reward) {
return null return null
} }
const data = await apiResponse.json() return {
const validatedApiRewards = isNewEndpoint ...reward,
? validateCategorizedRewardsSchema.safeParse(data) id: surprise.id,
: validateApiRewardSchema.safeParse(data) rewardType: surprise.rewardType,
rewardTierLevel: undefined,
if (!validatedApiRewards.success) { redeemLocation: surprise.redeemLocation,
getCurrentRewardFailCounter.add(1, { coupons: "coupon" in surprise ? surprise.coupon || [] : [],
locale: ctx.lang, categories:
error_type: "validation_error", "categories" in surprise ? surprise.categories || [] : [],
error: JSON.stringify(validatedApiRewards.error),
})
console.error(validatedApiRewards.error)
console.error(
"contentstack.surprises validation error",
JSON.stringify({
query: { locale: ctx.lang },
error: validatedApiRewards.error,
})
)
return null
} }
})
.flatMap((surprises) => (surprises ? [surprises] : []))
const rewardIds = validatedApiRewards.data return surprises
.map((reward) => reward?.rewardId)
.filter((rewardId): rewardId is string => !!rewardId)
.sort()
const cmsRewards = await getCmsRewards(ctx.lang, rewardIds)
if (!cmsRewards) {
return null
}
getCurrentRewardSuccessCounter.add(1)
const surprises: Surprise[] = validatedApiRewards.data
// TODO: Add predicates once legacy endpoints are removed
.filter((reward) => {
if (reward?.rewardType !== "Surprise") {
return false
}
if (!("coupon" in reward)) {
return false
}
const unwrappedCoupons =
reward.coupon.filter((coupon) => !coupon.unwrapped) || []
if (unwrappedCoupons.length === 0) {
return false
}
return true
})
.map((surprise) => {
const reward = cmsRewards.find(
({ reward_id }) => surprise.rewardId === reward_id
)
if (!reward) {
return null
}
return {
...reward,
id: surprise.id,
rewardType: surprise.rewardType,
rewardTierLevel: undefined,
redeemLocation: surprise.redeemLocation,
coupons: "coupon" in surprise ? surprise.coupon || [] : [],
categories:
"categories" in surprise ? surprise.categories || [] : [],
}
})
.flatMap((surprises) => (surprises ? [surprises] : []))
return surprises
},
"1h"
)
}), }),
unwrap: protectedProcedure unwrap: protectedProcedure
.input(rewardsUpdateInput) .input(rewardsUpdateInput)