proxy-pool/internal/adapters/redisactivity/scripts/bind_drain_ticket.lua
youfak 88d5ac24d4
Some checks are pending
ci / proto (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
ci / integration (push) Waiting to run
feat: bind drain tickets to full snapshots
2026-08-02 11:02:19 +08:00

66 lines
2.5 KiB
Lua

local tickets_key = KEYS[1]
local owners_key = KEYS[2]
local worker_index_key = KEYS[3]
local proxy_id = ARGV[1]
local worker_id = ARGV[2]
local assignment_epoch = tonumber(ARGV[3])
local required_epoch = tonumber(ARGV[4])
local session_id = ARGV[5]
local version = tonumber(ARGV[6])
local snapshot_epoch = tonumber(ARGV[7])
local checksum = ARGV[8]
local function reply(status)
return cjson.encode({status = status})
end
local function decode_table(raw)
if not raw then
return nil
end
local ok, value = pcall(cjson.decode, raw)
if not ok or type(value) ~= 'table' then
return nil
end
return value
end
local function valid_checksum(value)
return type(value) == 'string' and string.len(value) == 64 and string.match(value, '^[0-9a-f]+$') ~= nil
end
if type(proxy_id) ~= 'string' or proxy_id == '' or type(worker_id) ~= 'string' or worker_id == '' or
not assignment_epoch or assignment_epoch <= 0 or not required_epoch or required_epoch <= assignment_epoch or
type(session_id) ~= 'string' or session_id == '' or not version or version <= 0 or
not snapshot_epoch or snapshot_epoch < required_epoch or not valid_checksum(checksum) then
return reply('invalid')
end
local ticket = decode_table(redis.call('HGET', tickets_key, proxy_id))
local assignment = decode_table(redis.call('HGET', owners_key, proxy_id))
if not ticket or ticket.version ~= 1 or ticket.proxyId ~= proxy_id or ticket.workerId ~= worker_id or
ticket.workerIndexKey ~= worker_index_key or tonumber(ticket.assignmentEpoch) ~= assignment_epoch or
tonumber(ticket.requiredSnapshotEpoch) ~= required_epoch or not assignment or assignment.version ~= 1 or
assignment.draining ~= true or assignment.workerId ~= worker_id or tonumber(assignment.epoch) ~= assignment_epoch then
return reply('stale')
end
local current_epoch = tonumber(ticket.snapshotOwnershipEpoch) or 0
local current_version = tonumber(ticket.snapshotVersion) or 0
if current_epoch > snapshot_epoch or (current_epoch == snapshot_epoch and current_version > version) then
return reply('ok')
end
if current_epoch == snapshot_epoch and current_version == version then
if ticket.sessionId ~= session_id or ticket.snapshotChecksum ~= checksum then
return reply('stale')
end
return reply('ok')
end
ticket.sessionId = session_id
ticket.snapshotVersion = version
ticket.snapshotOwnershipEpoch = snapshot_epoch
ticket.snapshotChecksum = checksum
redis.call('HSET', tickets_key, proxy_id, cjson.encode(ticket))
return reply('ok')