CacheService
Cosa fa
CacheService e il singleton che orchestra il caching delle richieste HTTP. Funzionalita principali:
- Background Refresh — quando una entry si avvicina alla scadenza (raggiunto
threshold), avvia un refresh asincrono in background senza bloccare il chiamante - Request Deduplication — richieste concorrenti per la stessa chiave condividono la stessa
Promise - Auto Cleanup — pulizia periodica delle entry scadute (ogni 60s se la strategy supporta TTL)
- TTL Support — Time-to-live per entry, con verifica di "troppo vecchio" via
maxAgeglobale
Delega la persistenza effettiva a una ICacheStrategy iniettata.
Singleton pattern
class CacheService implements ICacheService {
static getInstance(
httpClient?: IHttpClient,
cacheStrategy?: ICacheStrategy,
logger?: ILogger
): CacheService
static resetInstance(): void
}
- Prima chiamata:
httpCliente obbligatorio, throw altrimenti - Chiamate successive: ritorna l'istanza esistente, ignorando i parametri
resetInstance()— distrugge l'istanza corrente, utile per testing
const cache = CacheService.getInstance(httpClient, strategy)
// ... altrove:
const sameInstance = CacheService.getInstance() // stessa istanza
Configurazione init()
cache.init(backgroundRefreshConfig?: Partial<BackgroundRefreshConfig>): void
| Campo | Tipo | Default | Descrizione |
|---|---|---|---|
enabled | boolean | true | Abilita il background refresh |
threshold | number | 75 | Percentuale di TTL utilizzato oltre cui scatta il refresh (75 = al 75%) |
maxAge | number | 3_600_000 | Eta massima assoluta in ms (1 ora). Oltre, cache miss forzato |
cache.init({
enabled: true,
threshold: 80, // refresh quando resta il 20% del TTL
maxAge: 7_200_000, // max 2 ore
})
Chiama init() per avviare anche la pulizia automatica (interval 60s se la strategy supporta TTL).
API principale
fetchWithCache(config, cacheKey?, ttl?, forceRefresh?, skipSaveCache?)
fetchWithCache<T>(
config: AxiosRequestConfig,
cacheKey?: string,
ttl?: number,
forceRefresh?: boolean,
skipSaveCache?: boolean
): Promise<AxiosResponse<T>>
Il metodo principale. Flusso:
- Compone
cacheKeydi default come${method}_${url}se non passata - Se una richiesta con la stessa key e gia pending, ritorna quella (dedup)
- Se
!forceRefresh: legge da cache. Se trovata e non "troppo vecchia" (maxAge), ritorna subito e — sethresholdraggiunto — avvia background refresh - Altrimenti esegue la richiesta HTTP, salva in cache (a meno di
skipSaveCache) e ritorna
const users = await cache.fetchWithCache<User[]>(
{ url: '/users', method: 'GET' },
'users-list',
300_000 // 5 minuti
)
// Forza refresh
const fresh = await cache.fetchWithCache<User[]>(
{ url: '/users', method: 'GET' },
'users-list',
300_000,
true // forceRefresh
)
getCache(key, config)
Lettura diretta dalla cache, senza fallback al network. Ritorna null se assente o scaduta. Avvia background refresh se threshold raggiunto.
const cached = await cache.getCache<User[]>('users-list', { url: '/users' })
if (cached) console.log('hit', cached.data)
setCache(key, response, ttl?)
Salva manualmente una AxiosResponse in cache (es. risposta arrivata da un altro flusso).
clearCache(keyPrefix)
Rimuove dalla cache tutte le entry con chiave che inizia con keyPrefix.
cache.clearCache('users-') // invalida tutte le entry users-*
invalidateAll()
Svuota completamente la cache. Chiamata internamente da AuthService.logout().
prefetch(config, cacheKey?, ttl?)
Forza un fetch fresco e popola la cache. Utile dopo il login per dati frequentemente acceduti.
await cache.prefetch<User>({ url: '/me', method: 'GET' }, 'current-user', 600_000)
cleanExpiredItems()
Rimuove subito tutte le entry scadute (oltre alla pulizia automatica ogni 60s).
setAuthHandler(handler)
Propaga un IAuthHandler al client HTTP interno per retry automatico su 401.
destroy()
Ferma l'interval di cleanup e svuota i pending requests. Chiamare prima di resetInstance() o all'unmount dell'app.
Background refresh — meccanica
Una entry e considerata "da refreshare" se:
backgroundRefreshConfig.enabled === true- La entry ha
expiry (eta / TTL) * 100 >= thresholdeta < maxAge
Il refresh viene eseguito in background con header X-Background-Refresh: true aggiunto alla request — utile per il backend per loggarlo/escluderlo dalle metriche.
Promise del refresh in corso e tracciata in pendingRequests.Esempio: integrazione completa
import {
CacheService,
CacheStrategyFactory,
HttpClientFactory,
AuthStrategyFactory,
AuthServiceFactory,
} from '@pzeta/postgrest'
// 1. HTTP client + auth
const httpClient = HttpClientFactory.createFetchClient()
const strategy = AuthStrategyFactory.createJwtStrategy()
const auth = AuthServiceFactory.create(httpClient, strategy)
httpClient.setAuthStrategy(strategy)
httpClient.setAuthHandler(auth)
// 2. Cache singleton
const cache = CacheService.getInstance(
httpClient,
CacheStrategyFactory.createWithFallback()
)
cache.init({ threshold: 75, maxAge: 3_600_000 })
cache.setAuthHandler(auth)
// 3. Uso
const orders = await cache.fetchWithCache<Order[]>(
{ url: '/orders', method: 'GET' },
'orders-list',
60_000
)
Cleanup all'unmount
window.addEventListener('beforeunload', () => {
CacheService.getInstance().destroy()
CacheService.resetInstance()
})
Vedi anche
CacheStrategyFactory— selezione strategy con auto-fallbackIndexedDBCacheStrategy— strategy defaultCacheMetadata— value object con TTL/expiryPostgRESTClient
Cache
Sistema di caching multi-strategia con TTL, background refresh e request deduplication. Strategie IndexedDB, LocalStorage, SessionStorage, Memory e NoCache con auto-fallback.
CacheStrategyFactory
Factory statica per la creazione di tutte le strategie di cache. Espone metodi specifici, create(type, config?) dinamico e createWithFallback() con auto-fallback IndexedDB → SessionStorage → LocalStorage → Memory.