SimpleCacheGatewaysProvider
Overview
The SimpleCacheGatewaysProvider
wraps another gateway provider and caches the results for improved performance. It reduces the overhead of repeated gateway discovery calls while maintaining the benefits of dynamic gateway providers.
Installation
npm install @ar.io/wayfinder-core
Basic Usage
import {
SimpleCacheGatewaysProvider,
NetworkGatewaysProvider,
} from '@ar.io/wayfinder-core'
import { ARIO } from '@ar.io/sdk'
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new NetworkGatewaysProvider({
ario: ARIO.mainnet(),
}),
ttlSeconds: 60 * 60, // Cache for 1 hour
maxCacheSize: 1000,
})
const gateways = await provider.getGateways()
console.log('Available gateways:', gateways)
Configuration Options
SimpleCacheGatewaysProviderOptions
interface SimpleCacheGatewaysProviderOptions {
gatewaysProvider: GatewaysProvider
ttlSeconds?: number
maxCacheSize?: number
enableBackgroundRefresh?: boolean
refreshInterval?: number
}
Parameters
← Swipe to see more →
Parameter | Type | Default | Description |
---|---|---|---|
gatewaysProvider | GatewaysProvider | Required | The provider to wrap and cache |
ttlSeconds | number | 300 | Cache TTL in seconds (5 minutes) |
maxCacheSize | number | 100 | Maximum number of cached entries |
enableBackgroundRefresh | boolean | false | Enable background cache refresh |
refreshInterval | number | 60000 | Background refresh interval in ms |
← Swipe to see more →
Configuration Examples
Production Configuration
import {
SimpleCacheGatewaysProvider,
NetworkGatewaysProvider,
} from '@ar.io/wayfinder-core'
import { ARIO } from '@ar.io/sdk'
// Production caching with background refresh
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new NetworkGatewaysProvider({
ario: ARIO.mainnet(),
minStake: 50000,
maxGateways: 20,
}),
ttlSeconds: 30 * 60, // 30 minute cache
maxCacheSize: 100,
enableBackgroundRefresh: true,
refreshInterval: 5 * 60 * 1000, // Refresh every 5 minutes
})
Development Configuration
import {
SimpleCacheGatewaysProvider,
StaticGatewaysProvider,
} from '@ar.io/wayfinder-core'
// Development caching with short TTL
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new StaticGatewaysProvider({
gateways: ['http://localhost:3000', 'https://arweave.net'],
}),
ttlSeconds: 60, // 1 minute cache for development
maxCacheSize: 10,
})
High-Performance Configuration
import {
SimpleCacheGatewaysProvider,
NetworkGatewaysProvider,
} from '@ar.io/wayfinder-core'
import { ARIO } from '@ar.io/sdk'
// Optimized for high-performance applications
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new NetworkGatewaysProvider({
ario: ARIO.mainnet(),
minStake: 100000,
maxGateways: 10,
}),
ttlSeconds: 60 * 60, // 1 hour cache
maxCacheSize: 50,
enableBackgroundRefresh: true,
refreshInterval: 10 * 60 * 1000, // Background refresh every 10 minutes
})
Advanced Usage
Multi-Level Caching
import {
SimpleCacheGatewaysProvider,
NetworkGatewaysProvider,
StaticGatewaysProvider,
} from '@ar.io/wayfinder-core'
import { ARIO } from '@ar.io/sdk'
// Cache with fallback provider
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new NetworkGatewaysProvider({
ario: ARIO.mainnet(),
minStake: 50000,
}),
ttlSeconds: 30 * 60,
fallbackProvider: new StaticGatewaysProvider({
gateways: ['https://arweave.net', 'https://ar-io.net'],
}),
})
Smart Cache with Metrics
import { SimpleCacheGatewaysProvider } from '@ar.io/wayfinder-core'
class MetricsAwareCacheProvider extends SimpleCacheGatewaysProvider {
constructor(options) {
super(options)
this.metrics = {
hits: 0,
misses: 0,
refreshes: 0,
errors: 0,
}
}
async getGateways() {
const startTime = Date.now()
try {
const gateways = await super.getGateways()
// Track cache hit/miss
if (this.isCacheHit()) {
this.metrics.hits++
} else {
this.metrics.misses++
}
return gateways
} catch (error) {
this.metrics.errors++
throw error
}
}
async refresh() {
try {
await super.refresh()
this.metrics.refreshes++
} catch (error) {
this.metrics.errors++
throw error
}
}
getMetrics() {
const total = this.metrics.hits + this.metrics.misses
return {
...this.metrics,
hitRate: total > 0 ? this.metrics.hits / total : 0,
totalRequests: total,
}
}
resetMetrics() {
this.metrics = { hits: 0, misses: 0, refreshes: 0, errors: 0 }
}
}
// Usage
const metricsProvider = new MetricsAwareCacheProvider({
gatewaysProvider: new NetworkGatewaysProvider({ ario: ARIO.mainnet() }),
ttlSeconds: 300,
})
// Later, check metrics
console.log('Cache metrics:', metricsProvider.getMetrics())
Persistent Cache
import { SimpleCacheGatewaysProvider } from '@ar.io/wayfinder-core'
class PersistentCacheProvider extends SimpleCacheGatewaysProvider {
constructor(options) {
super(options)
this.storageKey = options.storageKey || 'wayfinder-gateway-cache'
this.loadFromStorage()
}
async getGateways() {
const gateways = await super.getGateways()
this.saveToStorage()
return gateways
}
loadFromStorage() {
if (typeof localStorage === 'undefined') return
try {
const stored = localStorage.getItem(this.storageKey)
if (stored) {
const { gateways, timestamp } = JSON.parse(stored)
const now = Date.now()
// Check if stored data is still valid
if (now - timestamp < this.options.ttlSeconds * 1000) {
this.cachedGateways = gateways
this.cacheTimestamp = timestamp
}
}
} catch (error) {
console.warn('Failed to load cache from storage:', error.message)
}
}
saveToStorage() {
if (typeof localStorage === 'undefined') return
if (!this.cachedGateways) return
try {
const data = {
gateways: this.cachedGateways,
timestamp: this.cacheTimestamp,
}
localStorage.setItem(this.storageKey, JSON.stringify(data))
} catch (error) {
console.warn('Failed to save cache to storage:', error.message)
}
}
clearStorage() {
if (typeof localStorage !== 'undefined') {
localStorage.removeItem(this.storageKey)
}
}
}
// Usage
const persistentProvider = new PersistentCacheProvider({
gatewaysProvider: new NetworkGatewaysProvider({ ario: ARIO.mainnet() }),
ttlSeconds: 60 * 60, // 1 hour
storageKey: 'my-app-gateways',
})
Methods
getGateways()
Returns cached gateways or fetches from the underlying provider if cache is expired.
const gateways = await provider.getGateways()
console.log('Gateways:', gateways)
refresh()
Forces a refresh of the cache, bypassing TTL.
await provider.refresh()
console.log('Cache refreshed')
clearCache()
Clears the current cache.
provider.clearCache()
console.log('Cache cleared')
getCacheInfo()
Returns information about the current cache state.
const info = provider.getCacheInfo()
console.log('Cache info:', info)
// { size: 1, lastUpdate: Date, ttl: 300, isExpired: false }
Error Handling
import { SimpleCacheGatewaysProvider } from '@ar.io/wayfinder-core'
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new NetworkGatewaysProvider({ ario: ARIO.mainnet() }),
ttlSeconds: 300,
})
try {
const gateways = await provider.getGateways()
console.log('Available gateways:', gateways)
} catch (error) {
switch (error.constructor.name) {
case 'CacheError':
console.error('Cache operation failed:', error.message)
break
case 'ProviderError':
console.error('Underlying provider failed:', error.message)
// Cache may still return stale data
break
default:
console.error('Unknown error:', error.message)
}
}
Performance Benefits
Cache Hit Rates
// Measure cache performance
const provider = new SimpleCacheGatewaysProvider({
gatewaysProvider: new NetworkGatewaysProvider({ ario: ARIO.mainnet() }),
ttlSeconds: 300,
})
let hits = 0
let misses = 0
for (let i = 0; i < 10; i++) {
const startTime = Date.now()
const gateways = await provider.getGateways()
const duration = Date.now() - startTime
if (duration < 10) {
// Likely a cache hit
hits++
console.log(`Request ${i + 1}: Cache hit (${duration}ms)`)
} else {
misses++
console.log(`Request ${i + 1}: Cache miss (${duration}ms)`)
}
// Wait between requests
await new Promise((resolve) => setTimeout(resolve, 1000))
}
console.log(`Cache hit rate: ${(hits / (hits + misses)) * 100}%`)
Testing
Unit Tests
import { SimpleCacheGatewaysProvider } from '@ar.io/wayfinder-core'
describe('SimpleCacheGatewaysProvider', () => {
let mockProvider
let cacheProvider
beforeEach(() => {
mockProvider = {
getGateways: jest.fn().mockResolvedValue(['https://gateway.com']),
}
cacheProvider = new SimpleCacheGatewaysProvider({
gatewaysProvider: mockProvider,
ttlSeconds: 60,
})
})
test('should cache gateway results', async () => {
// First call should hit the underlying provider
await cacheProvider.getGateways()
expect(mockProvider.getGateways).toHaveBeenCalledTimes(1)
// Second call should use cache
await cacheProvider.getGateways()
expect(mockProvider.getGateways).toHaveBeenCalledTimes(1)
})
test('should refresh cache when TTL expires', async () => {
// Mock Date.now to control time
const originalNow = Date.now
let currentTime = 1000000
Date.now = jest.fn(() => currentTime)
// First call
await cacheProvider.getGateways()
expect(mockProvider.getGateways).toHaveBeenCalledTimes(1)
// Advance time beyond TTL
currentTime += 70000 // 70 seconds
// Second call should refresh cache
await cacheProvider.getGateways()
expect(mockProvider.getGateways).toHaveBeenCalledTimes(2)
Date.now = originalNow
})
test('should handle provider errors gracefully', async () => {
mockProvider.getGateways.mockRejectedValue(new Error('Provider failed'))
await expect(cacheProvider.getGateways()).rejects.toThrow('Provider failed')
})
})
Best Practices
- Use in Production: Caching significantly improves performance for network providers
- Set Appropriate TTL: Balance between freshness and performance
- Enable Background Refresh: Keeps cache warm without blocking requests
- Monitor Cache Performance: Track hit rates and adjust TTL accordingly
- Handle Provider Failures: Implement fallback strategies for when providers fail
- Consider Memory Usage: Set appropriate maxCacheSize for your application
- Use Persistent Storage: For web applications, consider localStorage for cache persistence
Comparison with Other Providers
← Swipe to see more →
Feature | SimpleCacheGatewaysProvider | NetworkGatewaysProvider | StaticGatewaysProvider |
---|---|---|---|
Performance | High (cached) | Medium (network calls) | High (no network) |
Data Freshness | Medium (cached with TTL) | High (real-time) | Low (static) |
Network Dependency | Medium (periodic refresh) | High (every call) | None |
Memory Usage | Medium (cache storage) | Low | Low |
Complexity | Medium (cache management) | Low | Low |
Use Case | Production (performance) | Production (freshness) | Development/Testing |
← Swipe to see more →
Related Documentation
- Gateway Providers Overview: Compare all gateway providers
- NetworkGatewaysProvider: Dynamic network discovery
- StaticGatewaysProvider: Static gateway configuration
- Wayfinder Configuration: Main wayfinder setup