Class: Parse::Cache::Redis

Inherits:
Object
  • Object
show all
Defined in:
lib/parse/cache/redis.rb

Overview

Ergonomic Redis cache builder for Parse Stack. Composes a ConnectionPool of Moneta-Redis stores and carries an optional ‘namespace` that `Parse::Client` will pick up automatically — there is no need to also pass `cache_namespace:` to `Parse.setup` when using this wrapper.

Usage:

Parse.setup(
  cache: Parse::Cache::Redis.new(
    url: "redis://localhost:6379/0",
    namespace: "app_x",
    pool_size: 10,
  ),
  expires: 60,
  ...
)

The instance is a Moneta-compatible store (it delegates the four methods the Faraday caching middleware uses — ‘[]`, `key?`, `delete`, `store` — to a pooled backend), so it can be passed directly to `Parse.setup(cache:)` / `Parse::Client.new(cache:)`.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url:, namespace: nil, pool_size: 5, pool_timeout: 5, **moneta_options) ⇒ Redis

Returns a new instance of Redis.

Parameters:

  • url (String)

    Redis URL (e.g. ‘“redis://localhost:6379/0”`).

  • namespace (String, nil) (defaults to: nil)

    optional key prefix so multiple Parse apps can share one Redis without colliding. When non-nil, the namespace is automatically forwarded to the caching middleware as ‘cache_namespace:`.

  • pool_size (Integer) (defaults to: 5)

    number of pooled Moneta-Redis stores. Defaults to 5 (the Puma default thread count).

    **Sizing math (per Faraday request):**

    • cache hit: ‘key?` + `[]` = **2 checkouts**

    • GET miss + successful store: ‘key?` + 3 variant deletes (anonymous + master-key sibling + final key) + 1 `store` in `on_complete` = **up to 5 checkouts**

    • non-GET write (POST/PUT/DELETE): 3 variant deletes = **3 checkouts**

    The worst case (5) is on the write-through-after-miss path, not the hit path. Rule of thumb: start at ‘pool_size = RAILS_MAX_THREADS`, then bump it up if you observe `ConnectionPool::TimeoutError` in `parse.cache.error` notifications (the middleware swallows that error into a passthrough request rather than raising to the caller).

  • pool_timeout (Numeric) (defaults to: 5)

    seconds to wait for a backend checkout before raising ‘ConnectionPool::TimeoutError`. Defaults to 5s. The caching middleware catches that error and falls back to a passthrough request rather than raising to the caller.

  • moneta_options (Hash)

    extra options passed through to ‘Moneta.new(:Redis, …)` (e.g. `:db`, `:connect_timeout`). `expires: true` is set automatically so per-key TTLs supplied by the caching middleware (the `:expires` Faraday option) are honored by Redis. Pass `expires: false` here to opt out — but note that doing so causes cached responses to live forever, which is rarely what you want for a session-token-scoped response cache.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/parse/cache/redis.rb', line 73

def initialize(url:, namespace: nil, pool_size: 5, pool_timeout: 5, **moneta_options)
  @url = url
  @namespace = normalize_namespace(namespace)
  @pool_size = pool_size
  @pool_timeout = pool_timeout
  # Default expires: true so per-call `expires:` (the TTL the
  # Faraday caching middleware passes on store) is honored. The
  # Moneta-Redis adapter ignores per-call expires unless the
  # store was constructed with this flag. Without it, cached
  # session-scoped REST responses outlive their token's
  # validity. Callers can still pass `expires: false` to opt out.
  merged_options = { expires: true }.merge(moneta_options)
  @moneta_options = merged_options
  @closed = false
  @pool = Pool.new(size: pool_size, timeout: pool_timeout) do
    Moneta.new(:Redis, { url: url }.merge(merged_options))
  end
end

Instance Attribute Details

#namespaceString? (readonly)

Returns cache key namespace prefix (or nil if not set).

Returns:

  • (String, nil)

    cache key namespace prefix (or nil if not set).



32
33
34
# File 'lib/parse/cache/redis.rb', line 32

def namespace
  @namespace
end

#pool_sizeInteger (readonly)

Returns pool size.

Returns:

  • (Integer)

    pool size.



35
36
37
# File 'lib/parse/cache/redis.rb', line 35

def pool_size
  @pool_size
end

#urlString (readonly)

Returns Redis connection URL.

Returns:

  • (String)

    Redis connection URL.



38
39
40
# File 'lib/parse/cache/redis.rb', line 38

def url
  @url
end

Instance Method Details

#[](key) ⇒ Object



92
93
94
# File 'lib/parse/cache/redis.rb', line 92

def [](key)
  @pool[key]
end

#clearObject

Clear cached entries belonging to this wrapper. Required for ‘Parse::Client#clear_cache!` compatibility.

**Namespace-scoped when a namespace is set:** the wrapper walks ‘<namespace>:*` via Redis SCAN and DELs the matching keys, leaving other tenants on the same DB untouched. When no namespace is configured the wrapper falls back to `FLUSHDB` on the backing DB — same blast radius as previous versions, but only for unnamespaced deployments. To opt into the wide FLUSHDB explicitly (e.g. ops tooling), call #flush_db!.



118
119
120
121
122
123
124
125
# File 'lib/parse/cache/redis.rb', line 118

def clear
  if @namespace
    delete_keys_matching!("#{@namespace}:*")
  else
    @pool.clear
  end
  self
end

#closeObject

Close all pooled connections. Safe to call multiple times.



137
138
139
140
141
# File 'lib/parse/cache/redis.rb', line 137

def close
  return if @closed
  @closed = true
  @pool.close
end

#delete(key) ⇒ Object



100
101
102
# File 'lib/parse/cache/redis.rb', line 100

def delete(key)
  @pool.delete(key)
end

#flush_db!Object

Issue ‘FLUSHDB` on the backing Redis DB, regardless of whether a namespace is configured. Evicts every key on the selected DB, including unrelated tenants — use only for ops tooling that owns the whole DB.



131
132
133
134
# File 'lib/parse/cache/redis.rb', line 131

def flush_db!
  @pool.clear
  self
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/parse/cache/redis.rb', line 96

def key?(key)
  @pool.key?(key)
end

#store(key, value, options = {}) ⇒ Object



104
105
106
# File 'lib/parse/cache/redis.rb', line 104

def store(key, value, options = {})
  @pool.store(key, value, options)
end