Created
May 7, 2013 04:14
-
-
Save lloydmeta/5530215 to your computer and use it in GitHub Desktop.
Cleaning of Redis keys based on pattern and external keys dump file. This allows for easy cleanup of Redis keys based on any kind of key pattern without having to care about escaping characters, memory issues, etc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#encoding: utf-8 | |
require 'rubygems' | |
require 'bundler/setup' | |
require 'redis' | |
class RedisKeyCleaner | |
attr_accessor :redis, :temp_file_path | |
def initialize(redis, temp_file_path) | |
self.redis = redis | |
self.temp_file_path = temp_file_path | |
end | |
# returns number of keys deleted | |
def remove_from_redis(keys_group = []) | |
if redis.del(keys_group) == keys_group.size | |
keys_group.size | |
else | |
false | |
end | |
end | |
# def delete_in_groups | |
# end | |
# deleted_keys_count = 0 | |
# total_keys_count = 0 | |
# takes params inside a hash | |
# :batch_size defaults to 20 | |
# :verbose defaults to true | |
def delete_keys_in_temp_file(params = {}) | |
batch_size = params.fetch(:batch_size, 20) | |
verbose = params.fetch(:verbose, true) | |
total_keys_count = 0 | |
deleted_keys_count = 0 | |
File.foreach(temp_file_path).each_slice(batch_size) do |keys_group| | |
total_keys_count = total_keys_count + keys_group.size | |
if removed_keys_count = remove_from_redis(strip_keys_group(keys_group)) | |
puts "Successfully deleted key group of size #{keys_group.size}" if verbose | |
deleted_keys_count = deleted_keys_count + removed_keys_count | |
else | |
puts "Failed to delete: #{keys_group.inspect}" if verbose | |
end | |
end | |
{total_keys_count: total_keys_count, deleted_keys_count: deleted_keys_count} | |
end | |
def dump_matching_keys_to_temp_file(pattern) | |
resque_keys = redis.keys(pattern) | |
File.open(temp_file_path, "w+") do |file| | |
resque_keys.each do |key| | |
file.puts key | |
end | |
end | |
end | |
def dump_and_delete(pattern, params = {}) | |
verbose = params.fetch(:verbose, true) | |
delete_temp_file = params.fetch(:delete_temp_file, true) | |
puts "Dumping ..." | |
dump_matching_keys_to_temp_file(pattern) | |
puts "Dumping finished !" | |
puts "Deleting dumped keys ..." | |
cleanup_job_stats = delete_keys_in_temp_file(params) | |
File.delete(temp_file_path) if delete_temp_file | |
puts "Deleted #{cleanup_job_stats[:deleted_keys_count]} keys out of #{cleanup_job_stats[:total_keys_count]}" | |
end | |
private | |
def strip_keys_group(keys_group = []) | |
keys_group.map{|element| element.strip} | |
end | |
end | |
# timeout is very important because the KEYS Redis command can be very slow | |
# with a large number of keys (the primary use-case for this kind of thing) | |
redis_config = { | |
host: "127.0.0.1", | |
port: 6390, | |
timeout: 60 | |
} | |
redis_cleaner = RedisKeyCleaner.new(Redis.new(redis_config), "./borked_keys") | |
# redis_cleaner.dump_matching_keys_to_temp_file("resque:resque-retry*PatriotsTracker*") <-- can be skipped if you already have one | |
cleanup_job_stats = redis_cleaner.delete_keys_in_temp_file(verbose: false) | |
puts "Deleted #{cleanup_job_stats[:deleted_keys_count]} keys out of #{cleanup_job_stats[:total_keys_count]}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment