Spaces:
Running
Running
File size: 2,915 Bytes
2ebf97a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | --[[
acquire_slot.lua v4
─────────────────────────────────────────────────────────────────────────────
Round-robin slot acquisition. Rounds are a rotation hint, never a lock cause.
Flow:
1. Read rr_ptr — starting key index.
2. Walk all keys. Skip failure-locked ones.
3. For each unlocked key, walk models from its midx.
Skip any model flagged with m{idx}:failed (error-mark from lock_key.lua).
For non-failed models, find first where rounds < maxRounds.
4. INCR rounds, advance rr_ptr, return slot.
5. If a model is error-marked, rotate midx past it and clear the flag.
6. If a model is naturally exhausted (rounds >= max),
rotate midx to next model and RESET that model's counter
so it can be reused — never lock for round exhaustion.
7. Return "none" only when ALL keys have an active failure lock.
Keys:
{prefix}:rr_ptr
{prefix}:key:{id}:lock (set only by lock_key.lua on upstream error)
{prefix}:key:{id}:midx
{prefix}:key:{id}:m{idx}:rounds
{prefix}:key:{id}:m{idx}:failed
]]
local prefix = KEYS[1]
local keyIds = cjson.decode(ARGV[1])
local models = cjson.decode(ARGV[2])
local maxRounds = tonumber(ARGV[3])
local numKeys = tonumber(ARGV[4])
local numModels = #models
local rrPtrK = prefix .. ":rr_ptr"
local startPtr = tonumber(redis.call("GET", rrPtrK) or "0") or 0
for attempt = 0, numKeys - 1 do
local keySlot = (startPtr + attempt) % numKeys
local keyId = keyIds[keySlot + 1]
local lockK = prefix .. ":key:" .. keyId .. ":lock"
if redis.call("EXISTS", lockK) == 0 then
local midxK = prefix .. ":key:" .. keyId .. ":midx"
local mIdx = tonumber(redis.call("GET", midxK) or "0") or 0
for mAttempt = 0, numModels - 1 do
local realMIdx = (mIdx + mAttempt) % numModels
local failedK = prefix .. ":key:" .. keyId .. ":m" .. realMIdx .. ":failed"
if redis.call("GET", failedK) == "1" then
local nextMIdx = (realMIdx + 1) % numModels
redis.call("SET", midxK, tostring(nextMIdx))
redis.call("DEL", failedK)
else
local roundsK = prefix .. ":key:" .. keyId .. ":m" .. realMIdx .. ":rounds"
local used = tonumber(redis.call("GET", roundsK) or "0") or 0
if used < maxRounds then
redis.call("INCR", roundsK)
redis.call("SET", rrPtrK, tostring((keySlot + 1) % numKeys))
redis.call("SET", midxK, tostring(realMIdx))
return { "ok", keyId, models[realMIdx + 1], tostring(realMIdx) }
else
local nextMIdx = (realMIdx + 1) % numModels
redis.call("SET", midxK, tostring(nextMIdx))
redis.call("SET", roundsK, "0")
end
end
end
end
end
return { "none" }
|