feat(etag): implement Phase 3.1 ETag support for efficient content fetching
- Add DailyNotificationETagManager for Android with conditional request handling - Add DailyNotificationETagManager for iOS with URLSession integration - Update DailyNotificationFetcher with ETag manager integration - Implement If-None-Match header support for conditional requests - Add 304 Not Modified response handling for cached content - Add ETag storage and validation with TTL management - Add network efficiency metrics and cache statistics - Add conditional request logic with fallback handling - Add ETag cache management and cleanup methods - Add phase3-1-etag-support.ts usage examples This implements Phase 3.1 ETag support for network optimization: - Conditional requests with If-None-Match headers - 304 Not Modified response handling for bandwidth savings - ETag caching with 24-hour TTL for efficient storage - Network metrics tracking cache hit ratios and efficiency - Graceful fallback when ETag requests fail - Comprehensive cache management and cleanup - Cross-platform implementation (Android + iOS) Files: 4 changed, 800+ insertions(+)
This commit is contained in:
317
examples/phase3-1-etag-support.ts
Normal file
317
examples/phase3-1-etag-support.ts
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Phase 3.1 ETag Support Implementation Usage Example
|
||||
*
|
||||
* Demonstrates ETag-based conditional requests for efficient content fetching
|
||||
* Shows 304 Not Modified handling, cache management, and network metrics
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
import { DailyNotification } from '@timesafari/daily-notification-plugin';
|
||||
|
||||
/**
|
||||
* Example: Configure ETag support for efficient fetching
|
||||
*/
|
||||
async function configureETagSupport() {
|
||||
try {
|
||||
console.log('Configuring ETag support for efficient fetching...');
|
||||
|
||||
// Configure with ETag support
|
||||
await DailyNotification.configure({
|
||||
storage: 'shared',
|
||||
ttlSeconds: 1800, // 30 minutes TTL
|
||||
prefetchLeadMinutes: 15,
|
||||
enableETagSupport: true // Enable ETag conditional requests
|
||||
});
|
||||
|
||||
console.log('✅ ETag support configured');
|
||||
|
||||
// The plugin will now:
|
||||
// - Send If-None-Match headers with cached ETags
|
||||
// - Handle 304 Not Modified responses efficiently
|
||||
// - Cache ETag values for future requests
|
||||
// - Track network efficiency metrics
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ ETag support configuration failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Demonstrate ETag conditional requests
|
||||
*/
|
||||
async function demonstrateETagConditionalRequests() {
|
||||
try {
|
||||
console.log('Demonstrating ETag conditional requests...');
|
||||
|
||||
// Configure ETag support
|
||||
await configureETagSupport();
|
||||
|
||||
// First request - will fetch content and cache ETag
|
||||
console.log('📡 First request (no ETag cached)...');
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
url: 'https://api.example.com/daily-content',
|
||||
time: '09:00',
|
||||
title: 'Daily Update',
|
||||
body: 'Your daily notification is ready'
|
||||
});
|
||||
|
||||
console.log('✅ First request completed - ETag cached');
|
||||
|
||||
// Second request - will use conditional request
|
||||
console.log('📡 Second request (ETag cached)...');
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
url: 'https://api.example.com/daily-content',
|
||||
time: '09:15',
|
||||
title: 'Daily Update',
|
||||
body: 'Your daily notification is ready'
|
||||
});
|
||||
|
||||
console.log('✅ Second request completed - conditional request used');
|
||||
|
||||
// The plugin will:
|
||||
// - Send If-None-Match header with cached ETag
|
||||
// - Receive 304 Not Modified if content unchanged
|
||||
// - Use cached content instead of downloading
|
||||
// - Update metrics to track efficiency
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ ETag conditional requests demonstration failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Check network efficiency metrics
|
||||
*/
|
||||
async function checkNetworkEfficiencyMetrics() {
|
||||
try {
|
||||
console.log('Checking network efficiency metrics...');
|
||||
|
||||
// Configure ETag support
|
||||
await configureETagSupport();
|
||||
|
||||
// Make some requests to generate metrics
|
||||
await demonstrateETagConditionalRequests();
|
||||
|
||||
// Get network metrics
|
||||
const metrics = await DailyNotification.getNetworkMetrics();
|
||||
|
||||
console.log('📊 Network Efficiency Metrics:');
|
||||
console.log(` Total Requests: ${metrics.totalRequests}`);
|
||||
console.log(` Cached Responses: ${metrics.cachedResponses}`);
|
||||
console.log(` Network Responses: ${metrics.networkResponses}`);
|
||||
console.log(` Errors: ${metrics.errors}`);
|
||||
console.log(` Cache Hit Ratio: ${(metrics.cacheHitRatio * 100).toFixed(1)}%`);
|
||||
|
||||
// Example output:
|
||||
// Total Requests: 4
|
||||
// Cached Responses: 2
|
||||
// Network Responses: 2
|
||||
// Errors: 0
|
||||
// Cache Hit Ratio: 50.0%
|
||||
|
||||
if (metrics.cacheHitRatio > 0.5) {
|
||||
console.log('✅ Good cache efficiency - ETag support is working well');
|
||||
} else {
|
||||
console.log('⚠️ Low cache efficiency - content may be changing frequently');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Network efficiency metrics check failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Manage ETag cache
|
||||
*/
|
||||
async function manageETagCache() {
|
||||
try {
|
||||
console.log('Managing ETag cache...');
|
||||
|
||||
// Configure ETag support
|
||||
await configureETagSupport();
|
||||
|
||||
// Get cache statistics
|
||||
const cacheStats = await DailyNotification.getCacheStatistics();
|
||||
|
||||
console.log('🗄️ ETag Cache Statistics:');
|
||||
console.log(` Total ETags: ${cacheStats.totalETags}`);
|
||||
console.log(` Valid ETags: ${cacheStats.validETags}`);
|
||||
console.log(` Expired ETags: ${cacheStats.expiredETags}`);
|
||||
|
||||
// Clean expired ETags
|
||||
if (cacheStats.expiredETags > 0) {
|
||||
console.log('🧹 Cleaning expired ETags...');
|
||||
await DailyNotification.cleanExpiredETags();
|
||||
console.log('✅ Expired ETags cleaned');
|
||||
}
|
||||
|
||||
// Reset metrics
|
||||
console.log('🔄 Resetting network metrics...');
|
||||
await DailyNotification.resetNetworkMetrics();
|
||||
console.log('✅ Network metrics reset');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ ETag cache management failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Handle ETag failures gracefully
|
||||
*/
|
||||
async function handleETagFailuresGracefully() {
|
||||
try {
|
||||
console.log('Handling ETag failures gracefully...');
|
||||
|
||||
// Configure ETag support
|
||||
await configureETagSupport();
|
||||
|
||||
// Schedule notification with potential ETag issues
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
url: 'https://api.example.com/unreliable-content',
|
||||
time: '09:00',
|
||||
title: 'Daily Update',
|
||||
body: 'Your daily notification is ready'
|
||||
});
|
||||
|
||||
console.log('✅ Notification scheduled with ETag fallback');
|
||||
|
||||
// The plugin will handle ETag failures by:
|
||||
// - Falling back to full content fetch if ETag fails
|
||||
// - Logging ETag errors for debugging
|
||||
// - Continuing with notification scheduling
|
||||
// - Updating error metrics
|
||||
|
||||
// Check metrics after potential failures
|
||||
const metrics = await DailyNotification.getNetworkMetrics();
|
||||
|
||||
if (metrics.errors > 0) {
|
||||
console.log(`⚠️ ${metrics.errors} ETag errors occurred - fallback used`);
|
||||
} else {
|
||||
console.log('✅ No ETag errors - all requests successful');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ ETag failure handling failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Monitor ETag performance over time
|
||||
*/
|
||||
async function monitorETagPerformance() {
|
||||
try {
|
||||
console.log('Monitoring ETag performance over time...');
|
||||
|
||||
// Configure ETag support
|
||||
await configureETagSupport();
|
||||
|
||||
// Monitor performance over multiple requests
|
||||
const monitoringInterval = setInterval(async () => {
|
||||
try {
|
||||
const metrics = await DailyNotification.getNetworkMetrics();
|
||||
const cacheStats = await DailyNotification.getCacheStatistics();
|
||||
|
||||
console.log('📊 Performance Snapshot:');
|
||||
console.log(` Cache Hit Ratio: ${(metrics.cacheHitRatio * 100).toFixed(1)}%`);
|
||||
console.log(` Total Requests: ${metrics.totalRequests}`);
|
||||
console.log(` Errors: ${metrics.errors}`);
|
||||
console.log(` Valid ETags: ${cacheStats.validETags}`);
|
||||
|
||||
// Stop monitoring if we have enough data
|
||||
if (metrics.totalRequests >= 10) {
|
||||
clearInterval(monitoringInterval);
|
||||
console.log('✅ Performance monitoring completed');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Performance monitoring error:', error);
|
||||
}
|
||||
}, 5000); // Check every 5 seconds
|
||||
|
||||
// Make some requests to generate data
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
url: 'https://api.example.com/daily-content',
|
||||
time: `09:${i.toString().padStart(2, '0')}`,
|
||||
title: 'Daily Update',
|
||||
body: 'Your daily notification is ready'
|
||||
});
|
||||
|
||||
// Wait between requests
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ ETag performance monitoring failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Optimize content fetching with ETags
|
||||
*/
|
||||
async function optimizeContentFetchingWithETags() {
|
||||
try {
|
||||
console.log('Optimizing content fetching with ETags...');
|
||||
|
||||
// Configure ETag support
|
||||
await configureETagSupport();
|
||||
|
||||
// Schedule multiple notifications for the same content
|
||||
const notifications = [
|
||||
{ time: '09:00', title: 'Morning Update' },
|
||||
{ time: '12:00', title: 'Midday Update' },
|
||||
{ time: '15:00', title: 'Afternoon Update' },
|
||||
{ time: '18:00', title: 'Evening Update' }
|
||||
];
|
||||
|
||||
for (const notification of notifications) {
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
url: 'https://api.example.com/daily-content', // Same URL
|
||||
time: notification.time,
|
||||
title: notification.title,
|
||||
body: 'Your daily notification is ready'
|
||||
});
|
||||
|
||||
console.log(`✅ Scheduled ${notification.title} at ${notification.time}`);
|
||||
}
|
||||
|
||||
// Check final metrics
|
||||
const metrics = await DailyNotification.getNetworkMetrics();
|
||||
|
||||
console.log('📊 Optimization Results:');
|
||||
console.log(` Total Requests: ${metrics.totalRequests}`);
|
||||
console.log(` Cached Responses: ${metrics.cachedResponses}`);
|
||||
console.log(` Cache Hit Ratio: ${(metrics.cacheHitRatio * 100).toFixed(1)}%`);
|
||||
|
||||
// With ETag support, we should see:
|
||||
// - First request: Network response (200 OK)
|
||||
// - Subsequent requests: Cached responses (304 Not Modified)
|
||||
// - High cache hit ratio (75%+)
|
||||
// - Reduced bandwidth usage
|
||||
// - Faster response times
|
||||
|
||||
if (metrics.cacheHitRatio >= 0.75) {
|
||||
console.log('✅ Excellent optimization - ETag support is highly effective');
|
||||
} else if (metrics.cacheHitRatio >= 0.5) {
|
||||
console.log('✅ Good optimization - ETag support is working well');
|
||||
} else {
|
||||
console.log('⚠️ Limited optimization - content may be changing frequently');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Content fetching optimization failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Export examples for use
|
||||
export {
|
||||
configureETagSupport,
|
||||
demonstrateETagConditionalRequests,
|
||||
checkNetworkEfficiencyMetrics,
|
||||
manageETagCache,
|
||||
handleETagFailuresGracefully,
|
||||
monitorETagPerformance,
|
||||
optimizeContentFetchingWithETags
|
||||
};
|
||||
Reference in New Issue
Block a user