feat: performance improvements

This commit is contained in:
Linus Flood
2024-11-05 12:53:57 +01:00
parent 249a5f6cb8
commit 7e4bbfb3e6
8 changed files with 290 additions and 300 deletions

View File

@@ -69,7 +69,6 @@ export default async function StepPage({
const hotelData = await getHotelData({ const hotelData = await getHotelData({
hotelId, hotelId,
language: lang, language: lang,
include: [HotelIncludeEnum.RoomCategories],
}) })
const roomAvailability = await getSelectedRoomAvailability({ const roomAvailability = await getSelectedRoomAvailability({
hotelId, hotelId,

View File

@@ -61,7 +61,6 @@ export default async function SelectRatePage({
serverClient().hotel.hotelData.get({ serverClient().hotel.hotelData.get({
hotelId: searchParams.hotel, hotelId: searchParams.hotel,
language: params.lang, language: params.lang,
include: [HotelIncludeEnum.RoomCategories],
}), }),
serverClient().hotel.availability.rooms({ serverClient().hotel.availability.rooms({
hotelId: parseInt(searchParams.hotel, 10), hotelId: parseInt(searchParams.hotel, 10),

View File

@@ -31,9 +31,7 @@ export default async function HotelPage() {
const lang = getLang() const lang = getLang()
const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY
const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID
const hotelData = await serverClient().hotel.get({ const hotelData = await serverClient().hotel.get()
include: ["RoomCategories"],
})
if (!hotelData) { if (!hotelData) {
return null return null
} }

View File

@@ -1,4 +1,4 @@
import { serverClient } from "@/lib/trpc/server" import { getCurrentFooter } from "@/lib/trpc/memoizedRequests"
import Image from "@/components/Image" import Image from "@/components/Image"
import { getLang } from "@/i18n/serverContext" import { getLang } from "@/i18n/serverContext"
@@ -8,9 +8,7 @@ import Navigation from "./Navigation"
import styles from "./footer.module.css" import styles from "./footer.module.css"
export default async function Footer() { export default async function Footer() {
const footerData = await serverClient().contentstack.base.currentFooter({ const footerData = await getCurrentFooter(getLang())
lang: getLang(),
})
if (!footerData) { if (!footerData) {
return null return null
} }

View File

@@ -61,18 +61,15 @@ export const getHotelData = cache(async function getMemoizedHotelData({
hotelId, hotelId,
language, language,
isCardOnlyPayment, isCardOnlyPayment,
include,
}: { }: {
hotelId: string hotelId: string
language: string language: string
isCardOnlyPayment?: boolean isCardOnlyPayment?: boolean
include?: HotelIncludeEnum[]
}) { }) {
return serverClient().hotel.hotelData.get({ return serverClient().hotel.hotelData.get({
hotelId, hotelId,
language, language,
isCardOnlyPayment, isCardOnlyPayment,
include,
}) })
}) })
@@ -120,6 +117,12 @@ export const getCurrentHeader = cache(async function getMemoizedCurrentHeader(
return serverClient().contentstack.base.currentHeader({ lang }) return serverClient().contentstack.base.currentHeader({ lang })
}) })
export const getCurrentFooter = cache(async function getMemoizedCurrentFooter(
lang: Lang
) {
return serverClient().contentstack.base.currentFooter({ lang })
})
export const getMyPagesNavigation = cache( export const getMyPagesNavigation = cache(
async function getMemoizedMyPagesNavigation() { async function getMemoizedMyPagesNavigation() {
return serverClient().contentstack.myPages.navigation.get() return serverClient().contentstack.myPages.navigation.get()

View File

@@ -1,4 +1,5 @@
import { metrics } from "@opentelemetry/api" import { metrics } from "@opentelemetry/api"
import { cache } from "react"
import { import {
MembershipLevel, MembershipLevel,
@@ -42,7 +43,7 @@ const getByLevelLoyaltyLevelFailCounter = meter.createCounter(
"trpc.contentstack.loyaltyLevel.byLevel-fail" "trpc.contentstack.loyaltyLevel.byLevel-fail"
) )
export async function getAllLoyaltyLevels(ctx: Context) { export const getAllLoyaltyLevels = cache(async (ctx: Context) => {
getAllLoyaltyLevelCounter.add(1) getAllLoyaltyLevelCounter.add(1)
// Ideally we should fetch all available tiers from API, but since they // Ideally we should fetch all available tiers from API, but since they
@@ -95,9 +96,10 @@ export async function getAllLoyaltyLevels(ctx: Context) {
getAllLoyaltyLevelSuccessCounter.add(1) getAllLoyaltyLevelSuccessCounter.add(1)
return validatedLoyaltyLevels.data return validatedLoyaltyLevels.data
} })
export async function getLoyaltyLevel(ctx: Context, level_id: MembershipLevel) { export const getLoyaltyLevel = cache(
async (ctx: Context, level_id: MembershipLevel) => {
getByLevelLoyaltyLevelCounter.add(1, { getByLevelLoyaltyLevelCounter.add(1, {
query: JSON.stringify({ lang: ctx.lang, level_id }), query: JSON.stringify({ lang: ctx.lang, level_id }),
}) })
@@ -146,7 +148,8 @@ export async function getLoyaltyLevel(ctx: Context, level_id: MembershipLevel) {
getByLevelLoyaltyLevelSuccessCounter.add(1) getByLevelLoyaltyLevelSuccessCounter.add(1)
return validatedLoyaltyLevels.data[0] return validatedLoyaltyLevels.data[0]
} }
)
export const loyaltyLevelQueryRouter = router({ export const loyaltyLevelQueryRouter = router({
byLevel: contentstackBaseProcedure byLevel: contentstackBaseProcedure

View File

@@ -1,11 +1,5 @@
import { z } from "zod" import { z } from "zod"
export const getHotelInputSchema = z.object({
include: z
.array(z.enum(["RoomCategories", "NearbyHotels", "Restaurants", "City"]))
.optional(),
})
export const getHotelsAvailabilityInputSchema = z.object({ export const getHotelsAvailabilityInputSchema = z.object({
cityId: z.string(), cityId: z.string(),
roomStayStartDate: z.string(), roomStayStartDate: z.string(),
@@ -54,18 +48,17 @@ export const getRatesInputSchema = z.object({
hotelId: z.string(), hotelId: z.string(),
}) })
export enum HotelIncludeEnum { export const HotelIncludeEnum = z.enum([
"RoomCategories", "RoomCategories",
"NearbyHotels", "NearbyHotels",
"Restaurants", "Restaurants",
"City", "City",
} ])
export const getHotelDataInputSchema = z.object({ export const getHotelDataInputSchema = z.object({
hotelId: z.string(), hotelId: z.string(),
language: z.string(), language: z.string(),
isCardOnlyPayment: z.boolean().optional(), isCardOnlyPayment: z.boolean().optional(),
include: z.array(z.nativeEnum(HotelIncludeEnum)).optional(),
}) })
export type HotelDataInput = z.input<typeof getHotelDataInputSchema> export type HotelDataInput = z.input<typeof getHotelDataInputSchema>

View File

@@ -1,4 +1,5 @@
import { metrics } from "@opentelemetry/api" import { metrics } from "@opentelemetry/api"
import { cache } from "react"
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
import * as api from "@/lib/api" import * as api from "@/lib/api"
@@ -34,7 +35,6 @@ import {
import { import {
getBreakfastPackageInputSchema, getBreakfastPackageInputSchema,
getHotelDataInputSchema, getHotelDataInputSchema,
getHotelInputSchema,
getHotelsAvailabilityInputSchema, getHotelsAvailabilityInputSchema,
getRatesInputSchema, getRatesInputSchema,
getRoomsAvailabilityInputSchema, getRoomsAvailabilityInputSchema,
@@ -165,25 +165,20 @@ async function getContentstackData(lang: Lang, uid?: string | null) {
return hotelPageData.data.hotel_page return hotelPageData.data.hotel_page
} }
export async function getHotelData( export const getHotelData = cache(
input: HotelDataInput, async (input: HotelDataInput, serviceToken: string) => {
serviceToken: string const { hotelId, language, isCardOnlyPayment } = input
) {
const { hotelId, language, include, isCardOnlyPayment } = input
const params: Record<string, string> = { const params: Record<string, string> = {
hotelId, hotelId,
language, language,
} }
if (include) { params.include = HotelIncludeEnum.options.join(",")
params.include = include.join(",")
}
getHotelCounter.add(1, { getHotelCounter.add(1, {
hotelId, hotelId,
language, language,
include,
}) })
console.info( console.info(
"api.hotels.hotelData start", "api.hotels.hotelData start",
@@ -196,6 +191,12 @@ export async function getHotelData(
headers: { headers: {
Authorization: `Bearer ${serviceToken}`, Authorization: `Bearer ${serviceToken}`,
}, },
// needs to clear default option as only
// cache or next.revalidate is permitted
cache: undefined,
next: {
revalidate: 60 * 30, // 30 minutes
},
}, },
params params
) )
@@ -205,7 +206,6 @@ export async function getHotelData(
getHotelFailCounter.add(1, { getHotelFailCounter.add(1, {
hotelId, hotelId,
language, language,
include,
error_type: "http_error", error_type: "http_error",
error: JSON.stringify({ error: JSON.stringify({
status: apiResponse.status, status: apiResponse.status,
@@ -234,7 +234,6 @@ export async function getHotelData(
getHotelFailCounter.add(1, { getHotelFailCounter.add(1, {
hotelId, hotelId,
language, language,
include,
error_type: "validation_error", error_type: "validation_error",
error: JSON.stringify(validateHotelData.error), error: JSON.stringify(validateHotelData.error),
}) })
@@ -252,7 +251,6 @@ export async function getHotelData(
getHotelSuccessCounter.add(1, { getHotelSuccessCounter.add(1, {
hotelId, hotelId,
language, language,
include,
}) })
console.info( console.info(
"api.hotels.hotelData success", "api.hotels.hotelData success",
@@ -267,14 +265,12 @@ export async function getHotelData(
} }
return validateHotelData.data return validateHotelData.data
} }
)
export const hotelQueryRouter = router({ export const hotelQueryRouter = router({
get: contentStackUidWithServiceProcedure get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => {
.input(getHotelInputSchema)
.query(async ({ ctx, input }) => {
const { lang, uid } = ctx const { lang, uid } = ctx
const { include } = input
const contentstackData = await getContentstackData(lang, uid) const contentstackData = await getContentstackData(lang, uid)
const hotelId = contentstackData?.hotel_page_id const hotelId = contentstackData?.hotel_page_id
@@ -289,11 +285,9 @@ export const hotelQueryRouter = router({
language: apiLang, language: apiLang,
} }
if (include) { params.include = HotelIncludeEnum.options.join(",")
params.include = include.join(",")
}
getHotelCounter.add(1, { hotelId, lang, include }) getHotelCounter.add(1, { hotelId, lang })
console.info( console.info(
"api.hotels.hotel start", "api.hotels.hotel start",
JSON.stringify({ JSON.stringify({
@@ -306,6 +300,12 @@ export const hotelQueryRouter = router({
headers: { headers: {
Authorization: `Bearer ${ctx.serviceToken}`, Authorization: `Bearer ${ctx.serviceToken}`,
}, },
// needs to clear default option as only
// cache or next.revalidate is permitted
cache: undefined,
next: {
revalidate: 60 * 30, // 30 minutes
},
}, },
params params
) )
@@ -315,7 +315,6 @@ export const hotelQueryRouter = router({
getHotelFailCounter.add(1, { getHotelFailCounter.add(1, {
hotelId, hotelId,
lang, lang,
include,
error_type: "http_error", error_type: "http_error",
error: JSON.stringify({ error: JSON.stringify({
status: apiResponse.status, status: apiResponse.status,
@@ -343,7 +342,6 @@ export const hotelQueryRouter = router({
getHotelFailCounter.add(1, { getHotelFailCounter.add(1, {
hotelId, hotelId,
lang, lang,
include,
error_type: "validation_error", error_type: "validation_error",
error: JSON.stringify(validatedHotelData.error), error: JSON.stringify(validatedHotelData.error),
}) })
@@ -387,7 +385,7 @@ export const hotelQueryRouter = router({
}, },
] ]
getHotelSuccessCounter.add(1, { hotelId, lang, include }) getHotelSuccessCounter.add(1, { hotelId, lang })
console.info( console.info(
"api.hotels.hotel success", "api.hotels.hotel success",
JSON.stringify({ JSON.stringify({
@@ -773,7 +771,6 @@ export const hotelQueryRouter = router({
{ {
hotelId, hotelId,
language: ctx.lang, language: ctx.lang,
include: [HotelIncludeEnum.RoomCategories],
}, },
ctx.serviceToken ctx.serviceToken
) )