Skip to content

Instantly share code, notes, and snippets.

@0sc
Created April 30, 2023 22:05
Show Gist options
  • Save 0sc/74d925142b4c6335d531de167be0f62c to your computer and use it in GitHub Desktop.
Save 0sc/74d925142b4c6335d531de167be0f62c to your computer and use it in GitHub Desktop.
Basic LUA script for selectively moving elements from one Redis list to another.
-- Original use case was a quick and dirty migration of some overbloated repeated jobs
-- from a sidekiq job queue to another/temporary redis list
-- as part of an incident mitigation.
--
-- usage example:
-- redis.eval("return { KEYS, ARGV }", :keys => ["k1", "k2"], :argv => ["a1", "a2"])
-- EVAL "return ARGV[1]" 2 sidekiq:default moved:default "{\"class\":\"Something\"}"
--
-- KEY[1] is the original list to remove elements from
-- KEY[2] is the other list to move the removed elements to
-- ARGS[1] is the string to match elements against; matched elements are removed while others are ignored
local len = tonumber(redis.call('LLEN', KEYS[1]));
local res = {};
res["total"] = len;
local moved = 0;
local ignored = 0;
while len > 0 do
-- retrieve the last element in the list
local entry = redis.call('LINDEX', KEYS[1], -1);
-- check if entry starts with the given prefix
if (entry:find(ARGV[1], 1, true) == 1) then
-- matched
-- move it from this list to another list
-- alternatively delete it directly using LREM
redis.call("LMOVE", KEYS[1], KEYS[2], "RIGHT", "LEFT");
-- increment count
moved = moved + 1;
else
-- no match
-- increment ignored count
ignored = ignored + 1;
-- move it to the top of this list
-- our logic is checking the last item in the list
redis.call("LMOVE", KEYS[1], KEYS[1], "RIGHT", "LEFT");
end;
-- decrement loop counter
len = len - 1;
end;
res["moved"] = moved;
res["ignored"] = ignored;
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment