Class: Parse::Embeddings::Cache::MonetaStore
- Inherits:
-
Object
- Object
- Parse::Embeddings::Cache::MonetaStore
- Defined in:
- lib/parse/embeddings/cache.rb
Overview
Adapter exposing any Moneta-compatible key/value store ([] /
[]=, optionally store(key, value, expires:)) through the
get/set duck enable! expects — the persistent-L2
option. Point it at the same Redis your Parse.cache uses and
query-embed cache entries survive process restarts and are
shared across processes:
require "moneta" moneta = Moneta.new(:Redis, url: ENV["REDIS_URL"]) Parse::Embeddings::Cache.enable!( store: Parse::Embeddings::Cache::MonetaStore.new(moneta, ttl: 30 * 24 * 3600), )
Keys are namespaced (emb: by default) so the entries are
recognizable next to other application keys; values are the
raw vector Arrays (Moneta's own serializer handles encoding).
TTL is forwarded via Moneta's expires: option when the
backend supports it, ignored otherwise.
Fail-open by design: a backend error (Redis down, serialization hiccup) degrades to a cache miss / dropped write — the embed path must never fail because the CACHE is unhealthy.
The cross-process race the in-process LRU doesn't have applies here: two processes missing the same key concurrently both call the provider and both write. That is correct (embeddings are deterministic per key) and bounded — no locking is attempted.
Instance Method Summary collapse
- #get(key) ⇒ Array<Float>?
-
#initialize(moneta, ttl: nil, namespace: "emb:") ⇒ MonetaStore
constructor
A new instance of MonetaStore.
-
#set(key, vector) ⇒ Array<Float>
The vector, unchanged.
Constructor Details
#initialize(moneta, ttl: nil, namespace: "emb:") ⇒ MonetaStore
Returns a new instance of MonetaStore.
118 119 120 121 122 123 124 125 126 127 |
# File 'lib/parse/embeddings/cache.rb', line 118 def initialize(moneta, ttl: nil, namespace: "emb:") unless moneta.respond_to?(:[]) && moneta.respond_to?(:[]=) raise ArgumentError, "Parse::Embeddings::Cache::MonetaStore expects a Moneta-compatible " \ "store responding to #[] and #[]= (got #{moneta.class})." end @moneta = moneta @ttl = ttl && Float(ttl) @namespace = namespace.to_s end |
Instance Method Details
#get(key) ⇒ Array<Float>?
130 131 132 133 134 135 |
# File 'lib/parse/embeddings/cache.rb', line 130 def get(key) value = @moneta[@namespace + key] value.is_a?(Array) ? value : nil rescue StandardError nil end |
#set(key, vector) ⇒ Array<Float>
Returns the vector, unchanged.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/parse/embeddings/cache.rb', line 138 def set(key, vector) k = @namespace + key if @ttl && @moneta.respond_to?(:store) begin @moneta.store(k, vector, expires: @ttl) rescue ArgumentError # Hash-like backends define #store(key, value) with no # options arg, so the expires: form raises ArgumentError. # Fall back to a plain write (no expiry) rather than letting # the fail-open rescue below silently drop every vector. @moneta[k] = vector end else @moneta[k] = vector end vector rescue StandardError vector end |