Class: ConvertSdk::Stores::RedisStore
- Inherits:
-
Object
- Object
- ConvertSdk::Stores::RedisStore
- Defined in:
- lib/convert_sdk/stores/redis_store.rb
Overview
A first-party, in-tree store adapter backed by Redis — the cross-process answer to MemoryStore's per-process limitation.
Why Redis (FR49)
MemoryStore keeps state in a single process. Puma clusters, Sidekiq
worker fleets, and Lambda invocations each run in separate processes, so
sticky bucketing (Story 2.11) and goal deduplication (Story 4.3) that
round-trip through a MemoryStore are inconsistent across the fleet.
RedisStore shares that state through a Redis instance, giving every
process the same view.
Zero gemspec footprint
The redis gem is the user's dependency, never the SDK's: it is NOT a
gemspec runtime dependency and is +require+-d lazily inside #initialize
— and only when a client is built from connection options. Requiring this
file (which lib/convert_sdk.rb does unconditionally) therefore never
pulls in redis, so require "convert_sdk" stays green for users who do
not install it. If a caller asks RedisStore to build its own client
without redis installed, instantiation raises an actionable error naming
the gem to add — a wiring-time programmer error, sanctioned in the same
class as +ConvertSdk.create+'s argument validation, NOT a business path.
Construction
# Preferred: inject an existing client (connection reuse / pooling).
# No `require "redis"`, no `Redis.new` — works even where the adapter
# file is loaded without the gem present.
store = ConvertSdk::Stores::RedisStore.new(redis: Redis.new(url: ...))
# Or pass connection options; the adapter lazily requires `redis` and
# constructs the client itself.
store = ConvertSdk::Stores::RedisStore.new(url: "redis://localhost:6379/0")
An optional key_prefix namespaces every key (default "convert:") so the
SDK's keys do not collide with other tenants of the same Redis database.
Thin adapter — resilience lives upstream
This adapter is serialization + connection only. It does NOT rescue Redis client exceptions: DataStoreManager (Story 2.1) already wraps every +get+/+set+ in a rescue-log passthrough, degrading a raising store to +nil+/no-op instead of crashing the host. Duplicating that rescue here would swallow errors the manager is responsible for logging.
Cross-process consistency caveat
Visitor-data merges are a read-modify-write. In-process that sequence is atomic under DataStoreManager's mutex, but across processes sharing one Redis there is no such lock: concurrent writers race and the last write wins. This matches the JS SDK contract. The SDK does NOT use Lua scripts or +WATCH+/+MULTI+ to close that race — that is deliberately out of scope.
Sidekiq / Lambda deployment guidance: see the Epic 5 documentation.
Constant Summary collapse
- DEFAULT_KEY_PREFIX =
Default namespace prepended to every key written to Redis.
"convert:"
Instance Method Summary collapse
-
#get(key) ⇒ Object?
Read and deserialize the value stored under
key. -
#initialize(redis: nil, key_prefix: DEFAULT_KEY_PREFIX, **options) ⇒ RedisStore
constructor
A new instance of RedisStore.
-
#set(key, value) ⇒ Object
Serialize
valueto JSON and store it underkey, overwriting any existing value.
Constructor Details
#initialize(redis: nil, key_prefix: DEFAULT_KEY_PREFIX, **options) ⇒ RedisStore
Returns a new instance of RedisStore.
76 77 78 79 |
# File 'lib/convert_sdk/stores/redis_store.rb', line 76 def initialize(redis: nil, key_prefix: DEFAULT_KEY_PREFIX, **) @key_prefix = key_prefix @client = redis || build_client() end |
Instance Method Details
#get(key) ⇒ Object?
Read and deserialize the value stored under key.
86 87 88 89 |
# File 'lib/convert_sdk/stores/redis_store.rb', line 86 def get(key) raw = @client.get(namespaced(key)) raw.nil? ? nil : JSON.parse(raw) end |
#set(key, value) ⇒ Object
Serialize value to JSON and store it under key, overwriting any
existing value.
97 98 99 |
# File 'lib/convert_sdk/stores/redis_store.rb', line 97 def set(key, value) @client.set(namespaced(key), JSON.generate(value)) end |