zaqar/zaqar/queues/storage/redis/scripts/claim_messages.lua

88 lines
2.4 KiB
Lua

--[[
Copyright (c) 2014 Rackspace Hosting, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
See the License for the specific language governing permissions and
limitations under the License.
--]]
-- Read params
local msgset_key = KEYS[1]
local now = tonumber(ARGV[1])
local limit = tonumber(ARGV[2])
local claim_id = ARGV[3]
local claim_expires = tonumber(ARGV[4])
local msg_ttl = tonumber(ARGV[5])
local msg_expires = tonumber(ARGV[6])
-- Scan for up to 'limit' unclaimed messages
local BATCH_SIZE = 100
local start = 0
local claimed_msgs = {}
local found_unclaimed = false
while (#claimed_msgs < limit) do
local stop = (start + BATCH_SIZE - 1)
local msg_ids = redis.call('ZRANGE', msgset_key, start, stop)
if (#msg_ids == 0) then
break
end
start = start + BATCH_SIZE
-- TODO(kgriffs): Try moving claimed IDs to a different set
-- to avoid scanning through already-claimed messages.
for i, mid in ipairs(msg_ids) do
-- NOTE(kgriffs): Since execution of this script can not
-- happen in parallel, once we find the first unclaimed
-- message, the remaining messages will always be
-- unclaimed as well.
if not found_unclaimed then
local msg = redis.call('HMGET', mid, 'c', 'c.e')
if msg[1] == '' or tonumber(msg[2]) <= now then
found_unclaimed = true
end
end
if found_unclaimed then
local msg_expires_prev = redis.call('HGET', mid, 'e')
-- Found an unclaimed message, so claim it
redis.call('HMSET', mid,
'c', claim_id,
'c.e', claim_expires)
-- Will the message expire early?
if tonumber(msg_expires_prev) < msg_expires then
redis.call('HMSET', mid,
't', msg_ttl,
'e', msg_expires)
end
claimed_msgs[#claimed_msgs + 1] = mid
if (#claimed_msgs == limit) then
break
end
end
end
end
return claimed_msgs