104 lines
3.9 KiB
Lua
104 lines
3.9 KiB
Lua
-- batchDeleteCustomers.lua
|
|
-- Atomically deletes multiple customers and all their associated entity caches
|
|
-- ARGV[1]: JSON array of {orgId, env, customerId} objects
|
|
-- Returns: number of keys deleted
|
|
|
|
local customersJson = ARGV[1]
|
|
local customers = cjson.decode(customersJson)
|
|
local allKeysToDelete = {}
|
|
|
|
-- Helper function to add balance-related keys for a cache key
|
|
local function addBalanceKeys(keysToDelete, cacheKey, featureIds)
|
|
if not featureIds or #featureIds == 0 then
|
|
return
|
|
end
|
|
|
|
for _, featureId in ipairs(featureIds) do
|
|
local balanceKey = buildBalanceCacheKey(cacheKey, featureId)
|
|
table.insert(keysToDelete, balanceKey)
|
|
|
|
-- Get the balance HSET to find breakdown/rollover counts
|
|
local balanceData = redis.call("HGETALL", balanceKey)
|
|
if balanceData and #balanceData > 0 then
|
|
-- Convert array to hash table
|
|
local balanceHash = {}
|
|
for i = 1, #balanceData, 2 do
|
|
balanceHash[balanceData[i]] = balanceData[i + 1]
|
|
end
|
|
|
|
-- Delete rollover keys
|
|
local rolloverCount = tonumber(balanceHash["_rollover_count"]) or 0
|
|
for i = 0, rolloverCount - 1 do
|
|
table.insert(keysToDelete, buildRolloverCacheKey(cacheKey, featureId, i))
|
|
end
|
|
|
|
-- Delete breakdown keys
|
|
local breakdownCount = tonumber(balanceHash["_breakdown_count"]) or 0
|
|
for i = 0, breakdownCount - 1 do
|
|
table.insert(keysToDelete, buildBreakdownCacheKey(cacheKey, featureId, i))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Process each customer
|
|
for _, customerInfo in ipairs(customers) do
|
|
local orgId = customerInfo.orgId
|
|
local env = customerInfo.env
|
|
local customerId = customerInfo.customerId
|
|
|
|
-- Build versioned cache key using shared utility
|
|
local cacheKey = buildCustomerCacheKey(orgId, env, customerId)
|
|
|
|
-- Get the customer base JSON to find entity and feature IDs
|
|
local baseJson = redis.call("GET", cacheKey)
|
|
|
|
-- Skip if customer not in cache
|
|
if baseJson then
|
|
table.insert(allKeysToDelete, cacheKey)
|
|
local success, customer = pcall(cjson.decode, baseJson)
|
|
if success and customer then
|
|
local entityIds = customer._entityIds or {}
|
|
local balanceFeatureIds = customer._balanceFeatureIds or {}
|
|
|
|
-- Add customer balance keys (with rollover/breakdown)
|
|
addBalanceKeys(allKeysToDelete, cacheKey, balanceFeatureIds)
|
|
|
|
-- Process each entity
|
|
for _, entityId in ipairs(entityIds) do
|
|
local entityCacheKey = buildEntityCacheKey(orgId, env, customerId, entityId)
|
|
table.insert(allKeysToDelete, entityCacheKey)
|
|
|
|
-- Get entity to find its feature IDs
|
|
local entityJson = redis.call("GET", entityCacheKey)
|
|
if entityJson then
|
|
local entitySuccess, entity = pcall(cjson.decode, entityJson)
|
|
if entitySuccess and entity then
|
|
local entityFeatureIds = entity._balanceFeatureIds or {}
|
|
|
|
-- Add entity balance keys (with rollover/breakdown)
|
|
addBalanceKeys(allKeysToDelete, entityCacheKey, entityFeatureIds)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Use UNLINK instead of DEL for async deletion (non-blocking)
|
|
local deletedCount = 0
|
|
if #allKeysToDelete > 0 then
|
|
-- UNLINK has a limit, so batch in chunks of 1000 keys
|
|
local chunkSize = 1000
|
|
for i = 1, #allKeysToDelete, chunkSize do
|
|
local chunk = {}
|
|
for j = i, math.min(i + chunkSize - 1, #allKeysToDelete) do
|
|
table.insert(chunk, allKeysToDelete[j])
|
|
end
|
|
deletedCount = deletedCount + redis.call("UNLINK", unpack(chunk))
|
|
end
|
|
end
|
|
|
|
return deletedCount
|
|
|