fix: concurrent stale race, Redis expire leak, missing invalidation, UI Suspense
- Fix integration data cache: set pending synchronously before creating fetch to prevent concurrent stale-revalidation from spawning duplicate upstream calls - Redis cache handler: skip persisting entries with expire=0 (dynamic entries should not be stored in Redis) - Add missing invalidation: user.changePassword, group.updateGroup, group.transferOwnership - Move SearchEngineOptimization inside Suspense in root layout - Add Suspense fallback loader to root layout - Move searchParams resolution inside Suspense in login page
This commit is contained in:
6 files changed
+30
-21
No files matched your search
@@ -39,6 +39,11 @@ export const getCachedIntegrationData = async <T>(
|
||||
}
|
||||
}
|
||||
|
||||
// Set pending synchronously BEFORE creating the fetch promise to prevent
|
||||
// concurrent stale-revalidation from spawning duplicate upstream calls.
|
||||
const placeholder = existing ?? { data: undefined as T, timestamp: 0 };
|
||||
if (!existing) cache.set(key, placeholder);
|
||||
|
||||
const pending = fetcher()
|
||||
.then((data) => {
|
||||
cache.set(key, { data, timestamp: Date.now() });
|
||||
@@ -67,13 +72,9 @@ export const getCachedIntegrationData = async <T>(
|
||||
throw error;
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
existing.pending = pending;
|
||||
return existing.data;
|
||||
}
|
||||
placeholder.pending = pending;
|
||||
|
||||
cache.set(key, { data: undefined as T, timestamp: 0, pending });
|
||||
return pending;
|
||||
return existing ? existing.data : pending;
|
||||
};
|
||||
|
||||
export const invalidateIntegrationDataCache = (integrationId: string) => {
|
||||
|
||||
Reference in new issue
Block a user