47 lines
1.2 KiB
Lua
47 lines
1.2 KiB
Lua
|
|
-- Atomic ticket purchase script
|
||
|
|
-- KEYS[1]: event tickets key (e.g., "event:1:tickets")
|
||
|
|
-- KEYS[2]: event metadata key (e.g., "event:1:meta")
|
||
|
|
-- KEYS[3]: global stats key ("global:stats")
|
||
|
|
-- ARGV[1]: timestamp
|
||
|
|
-- ARGV[2]: purchase ID (UUID)
|
||
|
|
|
||
|
|
local ticketKey = KEYS[1]
|
||
|
|
local metaKey = KEYS[2]
|
||
|
|
local globalKey = KEYS[3]
|
||
|
|
local timestamp = ARGV[1]
|
||
|
|
local purchaseId = ARGV[2]
|
||
|
|
|
||
|
|
-- Check if event exists
|
||
|
|
if redis.call('EXISTS', metaKey) == 0 then
|
||
|
|
return {nil, "EVENT_NOT_FOUND"}
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Atomically pop a ticket from the list
|
||
|
|
local ticket = redis.call('LPOP', ticketKey)
|
||
|
|
|
||
|
|
if not ticket then
|
||
|
|
return {nil, "NO_TICKETS_AVAILABLE"}
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Update event metadata
|
||
|
|
local soldCount = redis.call('HINCRBY', metaKey, 'soldTickets', 1)
|
||
|
|
redis.call('HSET', metaKey, 'lastSoldAt', timestamp)
|
||
|
|
|
||
|
|
-- Update global stats
|
||
|
|
redis.call('HINCRBY', globalKey, 'totalSold', 1)
|
||
|
|
|
||
|
|
-- Store purchase record
|
||
|
|
local purchaseKey = 'purchase:' .. purchaseId
|
||
|
|
redis.call('HSET', purchaseKey, {
|
||
|
|
'ticketId', ticket,
|
||
|
|
'eventId', string.match(ticketKey, 'event:(%d+):tickets'),
|
||
|
|
'purchaseId', purchaseId,
|
||
|
|
'timestamp', timestamp,
|
||
|
|
'status', 'completed'
|
||
|
|
})
|
||
|
|
|
||
|
|
-- Set expiration for purchase record (24 hours)
|
||
|
|
redis.call('EXPIRE', purchaseKey, 86400)
|
||
|
|
|
||
|
|
return {ticket, "SUCCESS", soldCount}
|