RunCache provides a comprehensive event system that allows you to monitor and respond to various cache lifecycle events. This guide explains how to use the event system effectively in your applications.
Understanding the Event System
The event system allows you to:
Monitor cache operations like expiration, refetching, and invalidation
Execute custom logic when specific events occur
Implement logging, analytics, and debugging
Build reactive systems that respond to cache changes
RunCache supports both global event listeners (for all keys) and key-specific listeners (for specific keys or patterns).
Available Event Types
RunCache provides several event types you can subscribe to:
Event Type
Description
Event Object Properties
EXPIRE
Triggered when a cache entry expires
key, ttl, updatedAt
REFETCH
Triggered when a cache entry is refreshed
key, metadata
REFETCH_FAILURE
Triggered when a cache refresh fails
key, error, metadata
TAG_INVALIDATION
Triggered when a cache entry is invalidated by tag
key, tag
DEPENDENCY_INVALIDATION
Triggered when a cache entry is invalidated by dependency
key, dependencyKey
Global Event Listeners
Global event listeners are triggered for all cache entries that match the specified event type:
Expiry Events
// Listen for all expiry events
RunCache.onExpiry((event) => {
console.log(`Cache key ${event.key} expired at ${new Date(event.updatedAt + event.ttl).toISOString()}`);
});
Refetch Events
// Listen for all successful refetch events
RunCache.onRefetch((event) => {
console.log(`Cache key ${event.key} was refreshed at ${new Date().toISOString()}`);
});
// Listen for all refetch failure events
RunCache.onRefetchFailure((event) => {
console.error(`Failed to refresh cache key ${event.key}:`, event.error.message);
});
Tag Invalidation Events
// Listen for all tag invalidation events
RunCache.onTagInvalidation((event) => {
console.log(`Cache key ${event.key} was invalidated by tag: ${event.tag}`);
});
Dependency Invalidation Events
// Listen for all dependency invalidation events
RunCache.onDependencyInvalidation((event) => {
console.log(`Cache key ${event.key} was invalidated due to dependency on: ${event.dependencyKey}`);
});
Key-Specific Event Listeners
Key-specific event listeners are triggered only for cache entries with keys that match the specified key or pattern:
Key-Specific Expiry Events
// Listen for expiry of a specific key
RunCache.onKeyExpiry("api-data", (event) => {
console.log(`API data cache expired`);
});
// Listen for expiry of keys matching a pattern
RunCache.onKeyExpiry("user:*:profile", (event) => {
console.log(`User profile ${event.key} expired`);
});
Key-Specific Refetch Events
// Listen for refetch of a specific key
RunCache.onKeyRefetch("weather-data", (event) => {
console.log(`Weather data was refreshed`);
});
// Listen for refetch failures of keys matching a pattern
RunCache.onKeyRefetchFailure("api:*", (event) => {
console.error(`API data ${event.key} refresh failed:`, event.error.message);
});
Key-Specific Tag Invalidation Events
// Listen for tag invalidation of keys matching a pattern
RunCache.onKeyTagInvalidation("user:*:profile", (event) => {
console.log(`User profile ${event.key} was invalidated by tag: ${event.tag}`);
});
Key-Specific Dependency Invalidation Events
// Listen for dependency invalidation of a specific key
RunCache.onKeyDependencyInvalidation("dashboard:main", (event) => {
console.log(`Main dashboard was invalidated due to dependency on: ${event.dependencyKey}`);
});
Managing Event Listeners
Removing All Event Listeners
To remove all event listeners:
// Remove all event listeners
RunCache.clearEventListeners();
Removing Specific Event Listeners
To remove listeners for a specific event type:
// Remove all expiry event listeners
RunCache.clearEventListeners({
event: EVENT.EXPIRE
});
Removing Key-Specific Listeners
To remove listeners for a specific key or pattern:
// Remove refetch listeners for a specific key
RunCache.clearEventListeners({
event: EVENT.REFETCH,
key: "api-data"
});
// Remove refetch failure listeners for keys matching a pattern
RunCache.clearEventListeners({
event: EVENT.REFETCH_FAILURE,
key: "api:*"
});
Practical Event System Use Cases
1. Logging and Monitoring
Use events to implement comprehensive logging:
// Set up logging for all major events
RunCache.onExpiry((event) => {
logger.info(`Cache expired: ${event.key}`);
});
RunCache.onRefetch((event) => {
logger.info(`Cache refreshed: ${event.key}`);
});
RunCache.onRefetchFailure((event) => {
logger.error(`Cache refresh failed: ${event.key}`, event.error);
});
RunCache.onTagInvalidation((event) => {
logger.info(`Cache invalidated by tag: ${event.key} (tag: ${event.tag})`);
});
RunCache.onDependencyInvalidation((event) => {
logger.info(`Cache invalidated by dependency: ${event.key} (depends on: ${event.dependencyKey})`);
});
2. Implementing Retry Logic
Use events to implement retry logic for failed refetches:
// Set up retry logic with exponential backoff
RunCache.onRefetchFailure((event) => {
const retryCount = (event.metadata?.retryCount || 0) + 1;
if (retryCount <= 3) {
const delay = Math.pow(2, retryCount) * 1000; // Exponential backoff
console.log(`Retrying ${event.key} in ${delay}ms (attempt ${retryCount})`);
setTimeout(() => {
RunCache.refetch(event.key, {
metadata: { retryCount }
});
}, delay);
} else {
console.error(`Failed to refresh ${event.key} after ${retryCount} attempts`);
}
});
3. UI Updates
Use events to trigger UI updates when cache data changes:
// React component example
function UserProfile({ userId }) {
const [profile, setProfile] = useState(null);
useEffect(() => {
// Set up event listener for cache refreshes
RunCache.onKeyRefetch(`user:${userId}:profile`, () => {
// Update UI when profile is refreshed
RunCache.get(`user:${userId}:profile`)
.then(data => data && setProfile(JSON.parse(data)));
});
// Initial data fetch
RunCache.get(`user:${userId}:profile`)
.then(data => data && setProfile(JSON.parse(data)));
// Clean up listener on unmount
return () => {
RunCache.clearEventListeners({
event: EVENT.REFETCH,
key: `user:${userId}:profile`
});
};
}, [userId]);
// Render profile...
}
4. Cache Analytics
Use events to collect analytics about cache usage:
Use events to implement custom cascading update logic:
// When user data is refreshed, also refresh related data
RunCache.onKeyRefetch('user:*:profile', async (event) => {
const userId = event.key.split(':')[1];
// Refresh related data
await RunCache.refetch(`user:${userId}:recommendations`);
await RunCache.refetch(`user:${userId}:activity`);
});
Event Metadata
You can attach custom metadata to cache entries, which will be included in event objects:
Use specific key patterns to minimize unnecessary event processing:
// Too broad - triggers for all keys
RunCache.onKeyExpiry('*', (event) => {
// This will run for EVERY expiry
});
// Better - more specific pattern
RunCache.onKeyExpiry('api:*', (event) => {
// This will only run for API-related expirations
});
4. Clean Up Event Listeners
Remove event listeners when they're no longer needed:
// In a component or module initialization
function initializeModule() {
// Set up event listeners
RunCache.onKeyRefetch('module-data', handleRefetch);
// Return cleanup function
return () => {
RunCache.clearEventListeners({
event: EVENT.REFETCH,
key: 'module-data'
});
};
}
// Later, when shutting down
const cleanup = initializeModule();
// When module is unloaded
cleanup();
5. Avoid Circular Event Handling
Be careful not to create circular event handling patterns: