refactor: implement caching for user preferences using ServerCacheService to reduce database calls and improve performance
This commit is contained in:
@@ -110,11 +110,11 @@ size: "1000"; // Récupère TOUS les livres d'un coup
|
|||||||
|
|
||||||
### Phase 3 : Optimisation des Préférences
|
### Phase 3 : Optimisation des Préférences
|
||||||
|
|
||||||
- [ ] **3.1 Cacher les préférences utilisateur**
|
- [x] **3.1 Cacher les préférences utilisateur**
|
||||||
|
|
||||||
- Créer `PreferencesService.getCachedPreferences()`
|
- Utiliser `ServerCacheService.getOrSet()` dans `getPreferences()`
|
||||||
- TTL court (1 minute)
|
- TTL : 5 minutes (via DEFAULT)
|
||||||
- Invalidation manuelle lors des modifications
|
- Invalidation automatique lors des modifications dans `updatePreferences()`
|
||||||
|
|
||||||
- [ ] **3.2 Réduire les appels DB**
|
- [ ] **3.2 Réduire les appels DB**
|
||||||
- Grouper les appels de config Komga + préférences
|
- Grouper les appels de config Komga + préférences
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import type {
|
|||||||
import { defaultPreferences } from "@/types/preferences";
|
import { defaultPreferences } from "@/types/preferences";
|
||||||
import type { User } from "@/types/komga";
|
import type { User } from "@/types/komga";
|
||||||
import type { Prisma } from "@prisma/client";
|
import type { Prisma } from "@prisma/client";
|
||||||
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
|
|
||||||
export class PreferencesService {
|
export class PreferencesService {
|
||||||
static async getCurrentUser(): Promise<User> {
|
static async getCurrentUser(): Promise<User> {
|
||||||
@@ -20,7 +21,11 @@ export class PreferencesService {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getPreferences(): Promise<UserPreferences> {
|
/**
|
||||||
|
* Récupère les préférences depuis la DB (sans cache)
|
||||||
|
* Utilisé en interne par getCachedPreferences()
|
||||||
|
*/
|
||||||
|
private static async getPreferencesFromDB(): Promise<UserPreferences> {
|
||||||
try {
|
try {
|
||||||
const user = await this.getCurrentUser();
|
const user = await this.getCurrentUser();
|
||||||
const userId = parseInt(user.id, 10);
|
const userId = parseInt(user.id, 10);
|
||||||
@@ -57,6 +62,34 @@ export class PreferencesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les préférences avec cache (TTL: 1 minute)
|
||||||
|
* Utilise ServerCacheService pour éviter les appels DB répétés
|
||||||
|
*/
|
||||||
|
static async getPreferences(): Promise<UserPreferences> {
|
||||||
|
try {
|
||||||
|
const cacheService = await getServerCacheService();
|
||||||
|
const cacheKey = "preferences";
|
||||||
|
|
||||||
|
// Utiliser getOrSet avec un fetcher qui récupère depuis la DB
|
||||||
|
// Note: getOrSet ajoute automatiquement le user.id au cacheKey
|
||||||
|
// TTL par défaut (5 min) est acceptable pour les préférences
|
||||||
|
// Elles changent rarement et 5 min est un bon compromis
|
||||||
|
const preferences = await cacheService.getOrSet(
|
||||||
|
cacheKey,
|
||||||
|
async () => this.getPreferencesFromDB(),
|
||||||
|
"DEFAULT"
|
||||||
|
);
|
||||||
|
|
||||||
|
return preferences;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.PREFERENCES.FETCH_ERROR, {}, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async updatePreferences(preferences: Partial<UserPreferences>): Promise<UserPreferences> {
|
static async updatePreferences(preferences: Partial<UserPreferences>): Promise<UserPreferences> {
|
||||||
try {
|
try {
|
||||||
const user = await this.getCurrentUser();
|
const user = await this.getCurrentUser();
|
||||||
@@ -95,7 +128,7 @@ export class PreferencesService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
const result: UserPreferences = {
|
||||||
showThumbnails: updatedPreferences.showThumbnails,
|
showThumbnails: updatedPreferences.showThumbnails,
|
||||||
cacheMode: updatedPreferences.cacheMode as "memory" | "file",
|
cacheMode: updatedPreferences.cacheMode as "memory" | "file",
|
||||||
showOnlyUnread: updatedPreferences.showOnlyUnread,
|
showOnlyUnread: updatedPreferences.showOnlyUnread,
|
||||||
@@ -106,6 +139,17 @@ export class PreferencesService {
|
|||||||
circuitBreakerConfig:
|
circuitBreakerConfig:
|
||||||
updatedPreferences.circuitBreakerConfig as unknown as CircuitBreakerConfig,
|
updatedPreferences.circuitBreakerConfig as unknown as CircuitBreakerConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Invalider le cache des préférences après mise à jour
|
||||||
|
try {
|
||||||
|
const cacheService = await getServerCacheService();
|
||||||
|
await cacheService.delete("preferences");
|
||||||
|
} catch (cacheError) {
|
||||||
|
// Ne pas faire échouer la mise à jour si l'invalidation du cache échoue
|
||||||
|
// Les préférences seront rechargées au prochain appel
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AppError) {
|
if (error instanceof AppError) {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
Reference in New Issue
Block a user