Class: Philiprehberger::HttpClient::Cache
- Inherits:
-
Object
- Object
- Philiprehberger::HttpClient::Cache
- Defined in:
- lib/philiprehberger/http_client/cache.rb
Overview
Simple in-memory cache for GET responses. Respects Cache-Control headers (max-age, no-cache, no-store) and supports conditional requests via ETag and Last-Modified headers.
The store is bounded: once it holds max_entries entries, the least
recently used entry is evicted on the next insert. Both #lookup hits
and #refresh mark an entry as recently used.
Defined Under Namespace
Classes: CacheEntry
Constant Summary collapse
- DEFAULT_MAX_ENTRIES =
Default upper bound on the number of cached entries.
1000
Instance Attribute Summary collapse
-
#max_entries ⇒ Integer
readonly
Maximum number of entries retained before LRU eviction.
Instance Method Summary collapse
-
#clear! ⇒ void
Remove all entries from the cache.
-
#entry_for(uri) ⇒ CacheEntry?
Return the cache entry for conditional request headers.
-
#initialize(max_entries: DEFAULT_MAX_ENTRIES) ⇒ Cache
constructor
A new instance of Cache.
-
#lookup(uri) ⇒ Response?
Look up a cached response for the given URI.
-
#refresh(uri, response) ⇒ Response?
Refresh a stored entry after a 304 Not Modified revalidation.
-
#size ⇒ Integer
Return the number of cached entries.
-
#store(uri, response) ⇒ void
Store a response in the cache.
Constructor Details
#initialize(max_entries: DEFAULT_MAX_ENTRIES) ⇒ Cache
Returns a new instance of Cache.
28 29 30 31 32 33 34 35 36 |
# File 'lib/philiprehberger/http_client/cache.rb', line 28 def initialize(max_entries: DEFAULT_MAX_ENTRIES) unless max_entries.is_a?(Integer) && max_entries.positive? raise ArgumentError, "max_entries must be a positive Integer, got #{max_entries.inspect}" end @monitor = Monitor.new @store = {} @max_entries = max_entries end |
Instance Attribute Details
#max_entries ⇒ Integer (readonly)
Maximum number of entries retained before LRU eviction.
41 42 43 |
# File 'lib/philiprehberger/http_client/cache.rb', line 41 def max_entries @max_entries end |
Instance Method Details
#clear! ⇒ void
This method returns an undefined value.
Remove all entries from the cache.
135 136 137 |
# File 'lib/philiprehberger/http_client/cache.rb', line 135 def clear! @monitor.synchronize { @store.clear } end |
#entry_for(uri) ⇒ CacheEntry?
Return the cache entry for conditional request headers. Returns nil if no entry exists (even if expired).
71 72 73 74 |
# File 'lib/philiprehberger/http_client/cache.rb', line 71 def entry_for(uri) key = cache_key(uri) @monitor.synchronize { @store[key] } end |
#lookup(uri) ⇒ Response?
Look up a cached response for the given URI. Returns nil if not cached or expired. A hit marks the entry as the most recently used.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/philiprehberger/http_client/cache.rb', line 49 def lookup(uri) key = cache_key(uri) @monitor.synchronize do entry = @store[key] return nil unless entry if expired?(entry) # Keep entries with etag/last_modified for conditional requests @store.delete(key) unless entry.etag || entry.last_modified nil else touch(key, entry) entry.response end end end |
#refresh(uri, response) ⇒ Response?
Refresh a stored entry after a 304 Not Modified revalidation.
Resets stored_at and applies any fresh max-age, ETag, or
Last-Modified carried by the 304 response, then returns the stored
response (with its body) so the caller can serve cached content.
Marks the entry as most recently used. Returns nil when no entry exists
for the URI.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/philiprehberger/http_client/cache.rb', line 115 def refresh(uri, response) key = cache_key(uri) cc = parse_cache_control(response) @monitor.synchronize do entry = @store[key] return nil unless entry entry.stored_at = now entry.max_age = cc[:max_age] if cc[:max_age] entry.etag = response.headers['etag'] if response.headers['etag'] entry.last_modified = response.headers['last-modified'] if response.headers['last-modified'] touch(key, entry) entry.response end end |
#size ⇒ Integer
Return the number of cached entries.
142 143 144 |
# File 'lib/philiprehberger/http_client/cache.rb', line 142 def size @monitor.synchronize { @store.size } end |
#store(uri, response) ⇒ void
This method returns an undefined value.
Store a response in the cache.
Respects Cache-Control: no-store (does not cache). Evicts the least
recently used entry when the store exceeds max_entries.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/philiprehberger/http_client/cache.rb', line 83 def store(uri, response) return if no_store?(response) key = cache_key(uri) cc = parse_cache_control(response) entry = CacheEntry.new( response: response, stored_at: now, max_age: cc[:max_age], etag: response.headers['etag'], last_modified: response.headers['last-modified'] ) @monitor.synchronize do @store.delete(key) @store[key] = entry evict_lru end end |