feat: implement etag on fetch entities actions#182
Conversation
✅ Deploy Preview for qa-fnvirtual ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| @@ -3,6 +3,50 @@ import SummitAPIRequest from "../utils/build-json/SummitAPIRequest"; | |||
| import EventAPIRequest from "../utils/build-json/EventsAPIRequest"; | |||
| import SpeakersAPIRequest from "../utils/build-json/SpeakersAPIRequest"; | |||
There was a problem hiding this comment.
etagCache grows unbounded with no eviction strategy. In long,running sessions (conference attendees keeping tabs open for hours), this could consume significant memory.
Consider using a Map with a size limit:
const etagCache = new Map();
const MAX_CACHE_SIZE = 100;
// Before inserting:
if (etagCache.size >= MAX_CACHE_SIZE) {
const oldest = etagCache.keys().next().value;
etagCache.delete(oldest);
}|
|
||
| const byLowerCase = toFind => value => toLowerCase(value) === toFind; | ||
| const toLowerCase = value => value.toLowerCase(); | ||
| const getKeys = headers => Object.keys(headers); |
There was a problem hiding this comment.
These helper functions (byLowerCase, toLowerCase, getKeys, getHeaderCaseInsensitive) are unnecessary. The fetch Headers object is not a plain object, so Object.keys(headers) won't iterate it correctly.
Headers.get() is already case,insensitive by spec. You can replace all of this with:
const responseETAG = res.headers.get('etag');This is simpler and actually correct.
| const key = getKeys(headers).find(byLowerCase(headerName)); | ||
| return key ? headers[key] : undefined; | ||
| }; | ||
|
|
There was a problem hiding this comment.
This ETag cache may conflict with the real,time updates system. When Ably pushes an update and the sync strategies call these fetch functions to get fresh data, the cached ETag could cause a 304 response, returning stale data instead of the updated entity.
Scenario:
- User loads summit → cached with ETag
- Backend updates summit → Ably message triggers
synchEntityData fetchSummitByIdsendsIf,None,Matchwith old ETag- Server responds
304→ stale cached data returned
Consider exporting a clearEtagCache function to invalidate entries when real,time updates are received:
export const clearEtagCacheForUrl = (urlPattern) => {
for (const key of Object.keys(etagCache)) {
if (key.includes(urlPattern)) {
delete etagCache[key];
}
}
};Then call it from sync strategies before re,fetching.
| if (responseETAG) { | ||
| etagCache[cacheKey] = { etag: responseETAG, body: data }; | ||
| } | ||
| return data; |
There was a problem hiding this comment.
Non,200/304 status codes are silently swallowed here. If the server returns 401, 403, 404, or 500, the function just returns null with no indication of what went wrong.
Consider adding error logging:
if (!res.ok) {
console.error(`fetchWithEtag failed (${res.status}):`, url);
}
return null;| } | ||
|
|
||
| const apiUrlWithParams = EventAPIRequest.build(apiUrl); | ||
| const cacheKey = apiUrlWithParams; |
There was a problem hiding this comment.
Minor: cacheKey is always identical to apiUrlWithParams (same pattern repeats in every function below). Consider removing the cacheKey parameter from fetchWithEtag and just using the URL directly as the cache key inside the function. This would simplify all call sites from:
const cacheKey = apiUrlWithParams;
return fetchWithEtag(apiUrlWithParams, cacheKey);To just:
return fetchWithEtag(apiUrlWithParams);Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
…l time updates Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
dfdeea3 to
25cf3bf
Compare
What kind of change does this PR introduce?
Does this PR introduce a breaking change?
No
What needs to be documented once your changes are merged?
Nothing
ref: https://app.clickup.com/t/86b70mfce
Signed-off-by: Tomás Castillo tcastilloboireau@gmail.com