Skip to content

Instantly share code, notes, and snippets.

@bsa7
Created February 20, 2019 05:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bsa7/19b7ddd8d47913fd3d4e26167eff1d78 to your computer and use it in GitHub Desktop.
Save bsa7/19b7ddd8d47913fd3d4e26167eff1d78 to your computer and use it in GitHub Desktop.
redis namespaced wrapper for rails
module Api
module V2
module ApiHelper
## Общий метод генерации ключей для кэша redis
def self.redis_key(params)
params[:locale] = I18n.locale
params_keys = params.keys.map(&:to_s).sort.map(&:to_sym)
['.', params_keys.map { |key| "#{key}:#{params[key]}" }.join('&'), '.'].join
end
end
end
end
# frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# Расширяет стандартный класс - выдаёт список ключей кэша redis, так или иначе связанных с экземпляром класса
def redis_cache_keys
redis_key_prefix = "#{self.class.name.gsub(/^.+::/, '').singularize.underscore}_id"
[
$redis.keys_namespaced("*#{redis_key_prefix}:#{id}*"),
respond_to?(:name) ? $redis.keys_namespaced("*#{redis_key_prefix}:#{name}*") : []
].flatten
end
# Расширяет стандартный класс - выполняет сброс всех записей кэша redis для определённого экземпляра класса
def invalidate_cache
redis_cache_keys.each do |redis_key|
$redis.del_namespaced(redis_key)
end
end
end
redis_url = ENV['REDISCLOUD_URL'] || 'redis://localhost:6379'
module RedisCacheMethods
def self.key_include_namespace?(key)
key[Regexp.new("^#{ENV['REDIS_PREFIX']}-")] ? true : false
end
def self.key_namespaced(key)
if Rails.env == 'test'
key_include_namespace?(key) ? "TEST--#{key}" : "TEST--#{ENV['REDIS_PREFIX']}-#{key}"
else
key_include_namespace?(key) ? key : "#{ENV['REDIS_PREFIX']}-#{key}"
end
end
def del_namespaced(key)
redis_key = RedisCacheMethods.key_namespaced(key)
del(redis_key)
end
def get_namespaced(key)
redis_key = RedisCacheMethods.key_namespaced(key)
get(redis_key)
end
def set_namespaced(key, value, expires_in: 24.hours)
redis_key = RedisCacheMethods.key_namespaced(key)
set(redis_key, value)
expire(redis_key, expires_in.to_i)
end
def keys_namespaced(pattern = '*')
redis_pattern = RedisCacheMethods.key_namespaced(pattern)
keys(pattern)
end
def fetch(key, expires_in: 24.hours, options: nil, force: false)
redis_key = RedisCacheMethods.key_namespaced(key)
if block_given?
respond = get(redis_key)
if respond.nil? || force
puts(options[:cache_empty_message]) if options && options[:cache_empty_message]
respond = JSON.generate(Proc.new.call)
set(redis_key, respond)
expire(redis_key, expires_in.to_i)
else
puts(options[:cache_exist_message]) if options && options[:cache_exist_message]
end
JSON.parse(respond)
end
end
end
$redis = Redis::Namespace.new(ENV['REDIS_PREFIX'], redis: Redis.new(url: redis_url))
$redis.extend(RedisCacheMethods)
# Возвращает список id промокодов, использованных пользователем на определённую покупку
def user_used_promocode_ids(user_id:, purchase_id:)
redis_key = Api::V2::ApiHelper.redis_key({
type: :user_promocode_ids,
user_id: user_id,
purchase_id: purchase_id,
})
# redis_key example: ".locale:ru&purchase_id:100500&type:user_promocode_ids&user_id:11111."
$redis.fetch(redis_key, expires_in: Rails.configuration.REDIS.INTERVALS.LONG) do
purchase = Purchase.find(purchase_id)
user = User.find(user_id)
user_promocodes = user.promocodes.where("purchased_till < ?", purchase.created_at)
user_promocodes.ids
end
end
def purchase_something(user_id:, promocode_id:, purchase_id:)
purchase = Purchase.find(purchase_id)
...
purchase.invalidate_cache
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment