Skip to content

Commit

Permalink
lessen the stress to our backend from the api/cookies call (#54324)
Browse files Browse the repository at this point in the history
Co-authored-by: Hector Alfaro <[email protected]>
  • Loading branch information
Ebonsignori and hectorsector authored Feb 10, 2025
1 parent 3db10d2 commit dfe64ef
Showing 1 changed file with 39 additions and 20 deletions.
59 changes: 39 additions & 20 deletions src/events/components/dotcom-cookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,69 @@ type DotcomCookies = {

let cachedCookies: DotcomCookies | null = null
let inFlightPromise: Promise<DotcomCookies> | null = null
let tries = 0

const GET_COOKIES_ENDPOINT = '/api/cookies'
const MAX_TRIES = 3
const LOCAL_STORAGE_KEY = 'dotcomCookies'

// Fetches httpOnly cookies from the server and cache the result
// We use an in-flight promise to avoid duplicate requests
// Fetches httpOnly cookies from the server and caches the result.
// We don't want to do this every time because of the load it would place on our servers
// So on success, the data is stored in local storage and reused on subsequent loads
// On failure, returns default empty values
// If a user is staff and they didn't happen to be logged in when these cookies were saved,
// we can instruct them as needed to update the cookies and correctly set the isStaff flag.
async function fetchCookies(): Promise<DotcomCookies> {
// Return the cached object if we have it in memory.
if (cachedCookies) {
return cachedCookies
}

// If request is already in progress, return the same promise
if (inFlightPromise) {
return inFlightPromise
}

if (tries > MAX_TRIES) {
// In prod, fail without a serious error
console.error('Failed to fetch cookies after 3 tries')
// In dev, be loud about the issue
if (process.env.NODE_ENV === 'development') {
throw new Error('Failed to fetch cookies after 3 tries')
// Try to load from local storage.
const storedCookies = localStorage.getItem(LOCAL_STORAGE_KEY)
if (storedCookies) {
try {
cachedCookies = JSON.parse(storedCookies) as DotcomCookies
return cachedCookies
} catch (e) {
console.error('Error parsing cookies from local storage:', e)
localStorage.removeItem(LOCAL_STORAGE_KEY)
}
}

return Promise.resolve({})
// If a request is already in progress, reuse it.
if (inFlightPromise) {
return inFlightPromise
}

// Make a single fetch request to the backend.
inFlightPromise = fetch(GET_COOKIES_ENDPOINT)
.then((response) => {
tries++
if (!response.ok) {
throw new Error(`Failed to fetch cookies: ${response.statusText}`)
}
return response.json() as Promise<DotcomCookies>
})
.then((data) => {
cachedCookies = data
// Store the fetched cookies in local storage for future use.
try {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(data))
} catch (e) {
console.error('Error storing cookies in local storage:', e)
}
return data
})
.catch((err) => {
console.error('Error fetching cookies:', err)
// On failure, return default values.
const defaultCookies: DotcomCookies = {
dotcomUsername: '',
isStaff: false,
}
cachedCookies = defaultCookies
return defaultCookies
})
.finally(() => {
// Clear the in-flight promise regardless of success or failure
// On success, subsequent calls will return the cached value
// On failure, subsequent calls will retry the request up to MAX_TRIES times
// Clear the in-flight promise regardless of success or failure.
inFlightPromise = null
})

Expand Down

0 comments on commit dfe64ef

Please sign in to comment.