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 ticket.sessionId == session_id then 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.snapshotChecksum ~= checksum then return reply('stale') end return reply('ok') end 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')