@breadstone/ziegel-platform-caching ​
Caching infrastructure and memory management for the ziegel platform. Provides multiple cache implementations, eviction policies, cache factories, and memory-efficient caching strategies for enterprise applications.
Caching: Enterprise caching with multiple strategies, eviction policies, and memory management for high-performance applications.
🚀 Overview ​
@breadstone/ziegel-platform-caching provides:
- Multiple Cache Types: Session, transient, and infinite caching strategies
- Eviction Policies: Configurable cache eviction and cleanup policies
- Cache Factory: Factory pattern for creating and managing cache instances
- Cache Items: Wrapper objects for cached data with metadata
- Caching Modes: Different caching behaviors and strategies
- Memory Management: Efficient memory usage and garbage collection support
📦 Installation ​
npm install @breadstone/ziegel-platform-caching
# or
yarn add @breadstone/ziegel-platform-caching🧩 Features & Usage Examples ​
Cache Factory Pattern ​
import { CacheFactory, CachingMode } from '@breadstone/ziegel-platform-caching';
// Create caches with different modes
const sessionCache = CacheFactory.createCache(CachingMode.Session);
const transientCache = CacheFactory.createCache(CachingMode.Transient);
const infiniteCache = CacheFactory.createCache(CachingMode.Infinite);
// Session cache - persists for the session
sessionCache.set('user-preferences', userPrefs);
// Transient cache - temporary storage
transientCache.set('temp-data', tempData, { ttl: 300 }); // 5 minutes
// Infinite cache - persists indefinitely
infiniteCache.set('app-constants', constants);Cache Items and Metadata ​
import { CacheItem, ICache } from '@breadstone/ziegel-platform-caching';
// Create cache item with metadata
const cacheItem = new CacheItem('user-data', userData, {
createdAt: Date.now(),
expiresAt: Date.now() + 3600000, // 1 hour
tags: ['user', 'profile'],
priority: 'high'
});
const cache: ICache = CacheFactory.createCache(CachingMode.Session);
cache.setItem(cacheItem);Eviction Policies ​
import { EvictionPolicy } from '@breadstone/ziegel-platform-caching';
// Configure different eviction policies
const lruCache = CacheFactory.createCache(CachingMode.Transient, {
evictionPolicy: EvictionPolicy.LRU, // Least Recently Used
maxSize: 1000
});
const fifoCache = CacheFactory.createCache(CachingMode.Transient, {
evictionPolicy: EvictionPolicy.FIFO, // First In First Out
maxSize: 500
});
const ttlCache = CacheFactory.createCache(CachingMode.Transient, {
evictionPolicy: EvictionPolicy.TTL, // Time To Live
defaultTtl: 3600
});Custom Cache Implementation ​
import { AbstractCache, ICache } from '@breadstone/ziegel-platform-caching';
class CustomDatabaseCache extends AbstractCache implements ICache {
private db: Database;
constructor(db: Database) {
super();
this.db = db;
}
async get<T>(key: string): Promise<T | null> {
const result = await this.db.query('SELECT value FROM cache WHERE key = ?', [key]);
return result ? JSON.parse(result.value) : null;
}
async set<T>(key: string, value: T, options?: CacheOptions): Promise<void> {
const serialized = JSON.stringify(value);
const expiresAt = options?.ttl ? Date.now() + (options.ttl * 1000) : null;
await this.db.query(
'INSERT OR REPLACE INTO cache (key, value, expires_at) VALUES (?, ?, ?)',
[key, serialized, expiresAt]
);
}
async remove(key: string): Promise<boolean> {
const result = await this.db.query('DELETE FROM cache WHERE key = ?', [key]);
return result.affectedRows > 0;
}
async clear(): Promise<void> {
await this.db.query('DELETE FROM cache');
}
async has(key: string): Promise<boolean> {
const result = await this.db.query('SELECT 1 FROM cache WHERE key = ?', [key]);
return !!result;
}
}
// Register custom cache with factory
CacheFactory.registerCache('database', CustomDatabaseCache);Cache Decorators ​
import { Cache, Cacheable, CacheEvict } from '@breadstone/ziegel-platform-caching';
class UserService {
private cache = CacheFactory.createCache(CachingMode.Session);
@Cacheable('users', { ttl: 3600 })
async getUser(id: string): Promise<User> {
return await this.userRepository.findById(id);
}
@CacheEvict('users')
async updateUser(id: string, data: Partial<User>): Promise<User> {
return await this.userRepository.update(id, data);
}
@Cache('user-list', { ttl: 1800 })
async getUsers(filter: UserFilter): Promise<User[]> {
return await this.userRepository.findAll(filter);
}
}Caching Modes in Detail ​
import { CachingMode, SessionCache, TransientCache, InfiniteCache } from '@breadstone/ziegel-platform-caching';
// Session Cache - Data persists for the current session
const sessionCache = new SessionCache();
sessionCache.set('user-session', sessionData);
// Cleared when browser/application session ends
// Transient Cache - Temporary data with TTL
const transientCache = new TransientCache();
transientCache.set('api-response', apiData, { ttl: 300 }); // 5 minutes
// Automatically cleaned up after TTL expires
// Infinite Cache - Persistent data
const infiniteCache = new InfiniteCache();
infiniteCache.set('app-config', configuration);
// Data persists until manually removed📚 Package Exports ​
import {
// Core Abstractions
AbstractCache,
ICache,
// Cache Implementations
SessionCache,
TransientCache,
InfiniteCache,
// Factory & Utils
CacheFactory,
CacheItem,
CachingMode,
EvictionPolicy
} from '@breadstone/ziegel-platform-caching';🔧 Advanced Usage ​
Cache Performance Monitoring ​
import { CacheFactory, CachingMode } from '@breadstone/ziegel-platform-caching';
const cache = CacheFactory.createCache(CachingMode.Session, {
enableMetrics: true,
onHit: (key) => console.log(`Cache hit: ${key}`),
onMiss: (key) => console.log(`Cache miss: ${key}`),
onEviction: (key, reason) => console.log(`Evicted ${key}: ${reason}`)
});
// Get cache statistics
const stats = cache.getStatistics();
console.log(`Hit rate: ${stats.hitRate}%`);
console.log(`Total operations: ${stats.totalOperations}`);Memory Management ​
import { CacheFactory } from '@breadstone/ziegel-platform-caching';
const cache = CacheFactory.createCache(CachingMode.Transient, {
maxMemoryUsage: 50 * 1024 * 1024, // 50MB
memoryCheckInterval: 30000, // 30 seconds
onMemoryPressure: () => {
// Custom cleanup logic
cache.evictLeastRecentlyUsed(100);
}
});Cache Warming ​
class ApplicationCache {
private cache = CacheFactory.createCache(CachingMode.Session);
async warmCache(): Promise<void> {
// Pre-populate frequently accessed data
const criticalData = await this.loadCriticalData();
for (const [key, value] of criticalData) {
await this.cache.set(key, value, {
ttl: 7200, // 2 hours
priority: 'high'
});
}
}
async preloadUserData(userId: string): Promise<void> {
const userData = await this.userService.getUser(userId);
const userPrefs = await this.userService.getPreferences(userId);
await this.cache.set(`user:${userId}`, userData);
await this.cache.set(`prefs:${userId}`, userPrefs);
}
}Cache Invalidation Strategies ​
import { CacheFactory, CachingMode } from '@breadstone/ziegel-platform-caching';
class CacheInvalidationService {
private cache = CacheFactory.createCache(CachingMode.Session);
// Tag-based invalidation
async invalidateByTag(tag: string): Promise<void> {
const keys = await this.cache.getKeysByTag(tag);
await Promise.all(keys.map(key => this.cache.remove(key)));
}
// Pattern-based invalidation
async invalidateByPattern(pattern: string): Promise<void> {
const keys = await this.cache.getKeys();
const matchingKeys = keys.filter(key => key.includes(pattern));
await Promise.all(matchingKeys.map(key => this.cache.remove(key)));
}
// Time-based cleanup
async cleanupExpired(): Promise<void> {
await this.cache.removeExpired();
}
}🎯 Integration Examples ​
React Hook Integration ​
import React, { useEffect, useState } from 'react';
import { CacheFactory, CachingMode } from '@breadstone/ziegel-platform-caching';
const cache = CacheFactory.createCache(CachingMode.Session);
function useCache<T>(key: string, fetcher: () => Promise<T>, ttl = 3600) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const loadData = async () => {
setLoading(true);
// Try cache first
let cachedData = await cache.get<T>(key);
if (cachedData) {
setData(cachedData);
setLoading(false);
return;
}
// Fetch and cache
try {
cachedData = await fetcher();
await cache.set(key, cachedData, { ttl });
setData(cachedData);
} finally {
setLoading(false);
}
};
loadData();
}, [key]);
return { data, loading };
}
// Usage
function UserProfile({ userId }: { userId: string }) {
const { data: user, loading } = useCache(
`user:${userId}`,
() => userApi.getUser(userId),
1800 // 30 minutes
);
if (loading) return <div>Loading...</div>;
return <div>{user?.name}</div>;
}API Response Caching ​
import { CacheFactory, CachingMode } from '@breadstone/ziegel-platform-caching';
class ApiService {
private cache = CacheFactory.createCache(CachingMode.Transient);
async get<T>(url: string, options: RequestOptions = {}): Promise<T> {
const cacheKey = this.generateCacheKey(url, options);
// Check cache first
const cached = await this.cache.get<T>(cacheKey);
if (cached) {
return cached;
}
// Make API request
const response = await fetch(url, options);
const data = await response.json();
// Cache response
const ttl = this.getTtlForEndpoint(url);
await this.cache.set(cacheKey, data, { ttl });
return data;
}
private generateCacheKey(url: string, options: RequestOptions): string {
return `api:${url}:${JSON.stringify(options)}`;
}
private getTtlForEndpoint(url: string): number {
// Different TTLs for different endpoints
if (url.includes('/user/')) return 1800; // 30 minutes
if (url.includes('/config/')) return 7200; // 2 hours
return 300; // 5 minutes default
}
}📚 API Documentation ​
For detailed API documentation, visit: API Docs
Related Packages ​
- @breadstone/ziegel-platform: Core platform services
- @breadstone/ziegel-core: Foundation utilities
- @breadstone/ziegel-platform-configuration: Configuration management
License ​
MIT
Issues ​
Please report bugs and feature requests in the Issue Tracker
Part of the ziegel Enterprise TypeScript Framework backend: 'memory', maxSize: 100, ttl: 300 // 5 minutes }, { name: 'l2-redis', backend: 'redis', connectionString: 'redis://localhost:6379', maxSize: 10000, ttl: 3600 // 1 hour }, { name: 'l3-disk', backend: 'filesystem', path: '/tmp/cache', maxSize: 100000, ttl: 86400 // 24 hours } ];
const tieredCache = new TieredCache(tiers);
// Data flows through tiers automatically await tieredCache.set('key', 'value'); const value = await tieredCache.get('key'); // Checks L1 -> L2 -> L3
### Write-Through and Write-Behind
```typescript
import { WriteThroughCache, WriteBehindCache } from '@ziegel/platform-caching';
// Write-through: writes go to cache and storage simultaneously
const writeThroughCache = new WriteThroughCache({
cache: cache,
storage: dataStorage,
consistency: 'strong'
});
// Write-behind: writes go to cache immediately, storage asynchronously
const writeBehindCache = new WriteBehindCache({
cache: cache,
storage: dataStorage,
batchSize: 100,
flushInterval: 5000,
consistency: 'eventual'
});Distributed Caching ​
Redis Backend ​
import { RedisCache, RedisConfig } from '@ziegel/platform-caching';
const redisConfig: RedisConfig = {
host: 'localhost',
port: 6379,
password: 'your-password',
db: 0,
maxRetries: 3,
retryDelay: 1000,
enableCluster: false,
keyPrefix: 'myapp:'
};
const redisCache = new RedisCache(redisConfig);
await redisCache.connect();
// Use Redis-specific features
await redisCache.expire('key', 3600);
await redisCache.persist('key'); // Remove expiration
const ttl = await redisCache.ttl('key');Redis Cluster Support ​
import { RedisClusterCache } from '@ziegel/platform-caching';
const clusterCache = new RedisClusterCache({
nodes: [
{ host: 'redis-1.example.com', port: 6379 },
{ host: 'redis-2.example.com', port: 6379 },
{ host: 'redis-3.example.com', port: 6379 }
],
enableReadyCheck: true,
maxRetriesPerRequest: 3
});
await clusterCache.connect();Memcached Backend ​
import { MemcachedCache } from '@ziegel/platform-caching';
const memcachedCache = new MemcachedCache({
servers: ['localhost:11211'],
options: {
maxKeySize: 250,
maxExpiration: 2592000, // 30 days
maxValue: 1048576 // 1MB
}
});Cache Patterns ​
Cache-Aside (Lazy Loading) ​
import { CacheAsidePattern } from '@ziegel/platform-caching';
class UserService {
private cache = new CacheAsidePattern(cacheManager.getCache('users'));
async getUser(userId: string): Promise<User> {
return this.cache.get(
`user:${userId}`,
async () => {
// Fallback to database if not in cache
return await this.userRepository.findById(userId);
},
{ ttl: 3600 }
);
}
async updateUser(userId: string, userData: Partial<User>): Promise<User> {
const user = await this.userRepository.update(userId, userData);
// Invalidate cache after update
await this.cache.delete(`user:${userId}`);
return user;
}
}Read-Through Cache ​
import { ReadThroughCache } from '@ziegel/platform-caching';
const readThroughCache = new ReadThroughCache({
cache: cache,
loader: async (key: string) => {
// Automatically load data when cache miss occurs
return await database.findByKey(key);
},
defaultTTL: 3600
});
// Cache miss triggers automatic loading
const data = await readThroughCache.get('some:key');Write-Around Cache ​
import { WriteAroundCache } from '@ziegel/platform-caching';
const writeAroundCache = new WriteAroundCache({
cache: cache,
storage: storage,
invalidateOnWrite: true
});
// Writes bypass cache, but invalidate cached data
await writeAroundCache.write('key', 'value');Cache Invalidation ​
Tag-Based Invalidation ​
import { TaggedCache } from '@ziegel/platform-caching';
const taggedCache = new TaggedCache(cache);
// Set cache with tags
await taggedCache.set('user:123', userData, {
tags: ['user', 'profile', 'user:123'],
ttl: 3600
});
await taggedCache.set('user:456', userData2, {
tags: ['user', 'profile', 'user:456'],
ttl: 3600
});
// Invalidate by tag
await taggedCache.invalidateByTag('user'); // Invalidates all user data
await taggedCache.invalidateByTags(['profile', 'user:123']);Event-Driven Invalidation ​
import { EventDrivenInvalidation } from '@ziegel/platform-caching';
const invalidator = new EventDrivenInvalidation(cache);
// Register invalidation rules
invalidator.addRule({
event: 'user.updated',
invalidate: (eventData) => [`user:${eventData.userId}`, `profile:${eventData.userId}`]
});
invalidator.addRule({
event: 'product.priceChanged',
invalidate: (eventData) => [`product:${eventData.productId}`, 'products:*']
});
// Events automatically trigger invalidation
eventBus.emit('user.updated', { userId: '123' });Time-Based Invalidation ​
import { TimeBasedInvalidation } from '@ziegel/platform-caching';
const timeInvalidator = new TimeBasedInvalidation(cache);
// Schedule invalidation
timeInvalidator.scheduleInvalidation('daily:stats', new Date('2024-01-01T00:00:00Z'));
// Recurring invalidation
timeInvalidator.scheduleRecurring('hourly:cache', '0 * * * *'); // Every hour
// Conditional TTL
await cache.set('session:token', token, {
ttl: (key, value) => {
return value.isAdmin ? 7200 : 3600; // Longer TTL for admin sessions
}
});Performance Monitoring ​
Cache Metrics ​
import { CacheMetrics, MetricsCollector } from '@ziegel/platform-caching';
const metrics = new CacheMetrics();
const collector = new MetricsCollector(cache, metrics);
// Get cache statistics
const stats = await metrics.getStats();
/*
{
hitRate: 0.85,
missRate: 0.15,
totalRequests: 10000,
hits: 8500,
misses: 1500,
evictions: 50,
memoryUsage: 1048576,
keyCount: 500
}
*/
// Monitor performance over time
const timeSeries = await metrics.getTimeSeries('hit_rate', {
from: new Date('2024-01-01'),
to: new Date('2024-01-02'),
interval: '1h'
});Performance Alerts ​
import { PerformanceMonitor } from '@ziegel/platform-caching';
const monitor = new PerformanceMonitor(cache);
// Set up alerts
monitor.addAlert({
metric: 'hit_rate',
threshold: 0.8,
operator: 'less_than',
duration: 300, // 5 minutes
action: (alert) => {
console.warn('Low cache hit rate detected:', alert);
// Send notification or trigger optimization
}
});
monitor.addAlert({
metric: 'memory_usage',
threshold: 0.9,
operator: 'greater_than',
action: (alert) => {
// Trigger cache cleanup
cache.cleanup();
}
});Cache Optimization ​
import { CacheOptimizer } from '@ziegel/platform-caching';
const optimizer = new CacheOptimizer(cache);
// Analyze cache patterns
const analysis = await optimizer.analyzePatterns();
/*
{
hotKeys: ['user:123', 'config:app'],
coldKeys: ['temp:xyz'],
accessPatterns: {
'user:*': { frequency: 'high', size: 'medium' },
'config:*': { frequency: 'low', size: 'small' }
},
recommendations: [
'Increase TTL for config keys',
'Consider pre-warming user data'
]
}
*/
// Apply optimizations
await optimizer.applyRecommendations(analysis.recommendations);Advanced Features ​
Cache Warming ​
import { CacheWarmer } from '@ziegel/platform-caching';
const warmer = new CacheWarmer(cache);
// Pre-populate cache with frequently accessed data
await warmer.warmCache([
{ key: 'popular:products', loader: () => getPopularProducts() },
{ key: 'config:app', loader: () => getAppConfig() },
{ key: 'user:stats', loader: () => getUserStats() }
]);
// Schedule warming
warmer.scheduleWarming('0 6 * * *', async () => {
// Warm cache every day at 6 AM
await warmer.warmPopularContent();
});Cache Partitioning ​
import { PartitionedCache } from '@ziegel/platform-caching';
const partitionedCache = new PartitionedCache({
partitions: [
{ name: 'users', maxSize: 1000, ttl: 3600 },
{ name: 'products', maxSize: 5000, ttl: 7200 },
{ name: 'sessions', maxSize: 10000, ttl: 1800 }
],
partitionStrategy: 'hash' // or 'range', 'custom'
});
// Data is automatically partitioned
await partitionedCache.set('user:123', userData); // Goes to 'users' partition
await partitionedCache.set('product:456', productData); // Goes to 'products' partitionConditional Caching ​
import { ConditionalCache } from '@ziegel/platform-caching';
const conditionalCache = new ConditionalCache(cache);
// Cache based on conditions
await conditionalCache.set('data', value, {
condition: (key, value) => {
// Only cache if value is expensive to compute
return value.computationTime > 1000;
},
ttl: 3600
});
// Cache with staleness tolerance
const result = await conditionalCache.get('key', {
staleWhileRevalidate: true,
maxStaleTime: 300 // Accept 5-minute stale data while revalidating
});Configuration ​
Cache Configuration ​
interface CacheConfig {
defaultTTL: number;
maxSize: number;
storageBackend: 'memory' | 'redis' | 'memcached' | 'filesystem';
enableCompression: boolean;
compressionThreshold: number;
enableMetrics: boolean;
evictionPolicy: 'lru' | 'lfu' | 'fifo' | 'random';
enableEncryption: boolean;
encryptionKey?: string;
enablePersistence: boolean;
persistencePath?: string;
}Advanced Configuration ​
const advancedConfig: CacheConfig = {
defaultTTL: 3600,
maxSize: 10000,
storageBackend: 'redis',
enableCompression: true,
compressionThreshold: 1024, // Compress values > 1KB
enableMetrics: true,
evictionPolicy: 'lru',
enableEncryption: true,
encryptionKey: process.env.CACHE_ENCRYPTION_KEY,
enablePersistence: true,
persistencePath: '/var/cache/ziegel',
// Redis-specific options
redis: {
host: 'localhost',
port: 6379,
db: 0,
keyPrefix: 'app:cache:',
enableCluster: false,
sentinel: {
enabled: false,
hosts: [{ host: 'localhost', port: 26379 }],
name: 'mymaster'
}
},
// Performance tuning
performance: {
enableBatching: true,
batchSize: 100,
batchDelay: 10,
connectionPoolSize: 10,
commandTimeout: 5000
}
};Integration Examples ​
Express.js Middleware ​
import { createCacheMiddleware } from '@ziegel/platform-caching/express';
const cacheMiddleware = createCacheMiddleware({
cache: cacheManager.getCache('http'),
keyGenerator: (req) => `${req.method}:${req.originalUrl}`,
ttl: 300,
varyBy: ['user-agent', 'accept-language']
});
app.use('/api/products', cacheMiddleware);React Query Integration ​
import { useCachedQuery } from '@ziegel/platform-caching/react';
function ProductList() {
const { data, isLoading } = useCachedQuery(
'products',
() => fetchProducts(),
{
cacheTime: 300000, // 5 minutes
staleTime: 60000 // 1 minute
}
);
return <div>{/* Render products */}</div>;
}GraphQL Caching ​
import { GraphQLCachePlugin } from '@ziegel/platform-caching/graphql';
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
new GraphQLCachePlugin({
cache: cacheManager.getCache('graphql'),
ttl: 300,
keyStrategy: 'operation-based'
})
]
});Best Practices ​
Key Naming Conventions ​
// Use hierarchical naming
cache.set('user:123:profile', userProfile);
cache.set('product:456:details', productDetails);
cache.set('config:feature:flags', featureFlags);
// Include version in keys for schema changes
cache.set('user:123:v2', userDataV2);Error Handling ​
// Graceful degradation
async function getCachedData(key: string) {
try {
const cached = await cache.get(key);
if (cached) return cached;
} catch (error) {
console.warn('Cache error:', error);
// Fall back to primary data source
}
return await database.get(key);
}Memory Management ​
// Monitor memory usage
setInterval(async () => {
const stats = await cache.getStats();
if (stats.memoryUsage > MAX_MEMORY_THRESHOLD) {
await cache.cleanup();
}
}, 60000); // Check every minuteMigration Guide ​
From node-cache ​
// Before (node-cache)
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 });
cache.set('key', 'value');
const value = cache.get('key');
// After (ziegel-platform-caching)
import { CacheManager } from '@ziegel/platform-caching';
const cache = new CacheManager().getCache('default');
await cache.set('key', 'value');
const value = await cache.get('key');From Redis ​
// Before (raw Redis)
const redis = require('redis');
const client = redis.createClient();
await client.set('key', JSON.stringify(value));
const data = JSON.parse(await client.get('key'));
// After (ziegel-platform-caching)
import { RedisCache } from '@ziegel/platform-caching';
const cache = new RedisCache(config);
await cache.set('key', value); // Automatic serialization
const data = await cache.get('key'); // Automatic deserializationAPI Reference ​
For complete API documentation, see the API Reference.
Related Packages ​
ziegel-platform- Core platform servicesziegel-platform-configuration- Configuration management