Add performance optimizations and component refactors
- Cache read-heavy public API routes via redisCache (leaderboard, values, shop, articles, photos, guilds, teams, staff, users, home, radio, badges) - Add single-flight and bounded-memory cache layer with unit tests - Parallelize independent DB queries on search, rares, shop, staff, polls and profile pages - Push radio points leaderboard aggregation to SQL with a LIMIT - Split studio-client and import-furni-client into focused modules - Clean up next.config.ts
This commit is contained in:
1 parent
54f2bc5e0c
commit
f285a7cd98
42 files changed
+1616
-1205
No files matched your search
@@ -29,6 +29,10 @@ const IS_PRERENDER =
|
||||
|
||||
class SiteSettings {
|
||||
private cache: { map: Map<string, string>; expiresAt: number } | null = null;
|
||||
// Single-flight: one request (re)loads the map, the rest await it — the
|
||||
// root layout reads settings on every render, so concurrent misses must
|
||||
// not each hammer Redis/DB (cache-stampede protection).
|
||||
private inFlight: Promise<Map<string, string>> | null = null;
|
||||
|
||||
private async loadFromDb(): Promise<Map<string, string>> {
|
||||
try {
|
||||
@@ -42,13 +46,7 @@ class SiteSettings {
|
||||
}
|
||||
}
|
||||
|
||||
private async load(): Promise<Map<string, string>> {
|
||||
if (this.cache !== null) {
|
||||
if (IS_PRERENDER || this.cache.expiresAt > Date.now()) {
|
||||
return this.cache.map;
|
||||
}
|
||||
}
|
||||
|
||||
private async loadFromCacheOrDb(): Promise<Map<string, string>> {
|
||||
if (redis) {
|
||||
try {
|
||||
const cached = await redis.get(REDIS_CACHE_KEY);
|
||||
@@ -85,6 +83,22 @@ class SiteSettings {
|
||||
return map;
|
||||
}
|
||||
|
||||
private async load(): Promise<Map<string, string>> {
|
||||
if (this.cache !== null) {
|
||||
if (IS_PRERENDER || this.cache.expiresAt > Date.now()) {
|
||||
return this.cache.map;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.inFlight) return this.inFlight;
|
||||
|
||||
const run = this.loadFromCacheOrDb().finally(() => {
|
||||
this.inFlight = null;
|
||||
});
|
||||
this.inFlight = run;
|
||||
return run;
|
||||
}
|
||||
|
||||
async getAll(): Promise<Map<string, string>> {
|
||||
return await this.load();
|
||||
}
|
||||
@@ -127,6 +141,7 @@ class SiteSettings {
|
||||
|
||||
async reload(): Promise<void> {
|
||||
this.cache = null;
|
||||
this.inFlight = null;
|
||||
if (redis) {
|
||||
try {
|
||||
await redis.del(REDIS_CACHE_KEY);
|
||||
|
||||
Reference in new issue
Block a user