Skip to content

Instantly share code, notes, and snippets.

@CiTroNaK
Forked from brasic/clear_redis_script.rb
Last active July 19, 2019 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CiTroNaK/fae7ae9265cbf6891d669a12b1f7b05e to your computer and use it in GitHub Desktop.
Save CiTroNaK/fae7ae9265cbf6891d669a12b1f7b05e to your computer and use it in GitHub Desktop.
Clear a large number of redis keys by pattern using SCAN and pipelining
#!/usr/bin/env ruby
require 'redis'
# Clear a large number of keys matching a pattern using SCAN and
# pipelining to avoid killing the server.
class ClearKeys
def initialize(pattern, url, postprocess_pattern=nil)
@redis = Redis.new(url: url)
@pattern = pattern
@postprocess_pattern = postprocess_pattern
end
def call
puts db_info
puts "Clearing #{@pattern}"
keys, time = timed { get_keys }
puts "#{keys.size} matching keys found in #{time} sec."
keys = postprocess(keys)
puts "#{keys.size} matching keys after postprocessing"
unless ENV['DRY_RUN']
puts "deleting..."
_, time = timed { clear(keys) }
puts "Deleted in #{time} sec."
puts db_info
end
end
def clear(keys)
keys.each_slice(500) do |chunk|
@redis.pipelined do
chunk.each do |key|
@redis.del key
end
end
end
end
def postprocess(keys)
return keys if !@postprocess_pattern
regex = Regexp.new(@postprocess_pattern)
keys.select{ |k| regex.match k }
end
def db_info
"DB stats: #{@redis.info['db0']}"
end
def timed(&block)
start = Time.now
result = block.call
elapsed = (Time.now - start).round(2)
return [result, elapsed]
end
def get_keys
@redis.scan_each(match: @pattern, count:1000).to_a
end
end
if ARGV[0].nil?
puts "Syntax: #{$0} REDIS_PATTERN [HOST] [REGEX]"
else
ClearKeys.new(ARGV[0], ARGV[1], ARGV[2]).call
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment