Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 49 additions & 48 deletions src/main/resources/lua/usage_update.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ local function getResult(status, currentMonthlyUsed, duplicate)
local currentRemaining = tonumber(redis.call('GET', KEYS[2]) or totalLimit)
local totalUsed = totalLimit - currentRemaining
local userRatio = 0
if totalLimit > 0 then userRatio = currentMonthlyUsed / totalLimit end
if totalLimit > 0 then
userRatio = currentMonthlyUsed / totalLimit
end

return {
totalUsed,
Expand All @@ -34,42 +36,43 @@ local function getResult(status, currentMonthlyUsed, duplicate)
}
end

-- 1. usage-event dedup 검사
-- 1) 동일 eventId 재처리 방지
if dedupTtlSeconds > 0 then
local firstSeen = redis.call('SET', KEYS[6], '1', 'NX', 'EX', dedupTtlSeconds)
if not firstSeen then
-- duplicate면 Java에서 상세 수치를 사용하지 않으므로 고정값만 반환한다.
return {0, 0, "DUPLICATE", 0, 0, -1, 1}
return {0, 0, 'DUPLICATE', 0, 0, -1, 1}
end
end

-- 2. 고객 정책 제약 로딩
-- 2) 고객별 제약 조회
local constraintsArray = redis.call('HGETALL', KEYS[4])
local constraints = {}
for i = 1, #constraintsArray, 2 do
constraints[constraintsArray[i]] = constraintsArray[i + 1]
end

local monthlyLimitStr = constraints['LIMIT:DATA:MONTHLY']
if monthlyLimitStr then monthlyLimit = tonumber(monthlyLimitStr) end
if monthlyLimitStr then
monthlyLimit = tonumber(monthlyLimitStr)
end

local currentMonthly = tonumber(redis.call('GET', KEYS[3]) or '0')

-- 3. 차단/제한 조건 검사
if constraints['BLOCK:ACCESS'] == "1" then
return getResult("MANUAL", currentMonthly, false)
-- 3) 차단/제한 조건 확인
if constraints['BLOCK:ACCESS'] == '1' then
return getResult('MANUAL', currentMonthly, false)
end

if appId ~= '' and constraints['BLOCK:APP:' .. appId] == "1" then
return getResult("APP_BLOCK", currentMonthly, false)
if appId ~= '' and constraints['BLOCK:APP:' .. appId] == '1' then
return getResult('APP_BLOCK', currentMonthly, false)
end

local blockStart = nil
local blockEnd = nil

local blockTimeRange = constraints['BLOCK:TIME']
if blockTimeRange then
local dashPos = string.find(blockTimeRange, "-", 1, true)
local dashPos = string.find(blockTimeRange, '-', 1, true)
if dashPos then
local startStr = string.sub(blockTimeRange, 1, dashPos - 1)
local endStr = string.sub(blockTimeRange, dashPos + 1)
Expand All @@ -81,20 +84,20 @@ end
if blockStart and blockEnd then
if blockStart < blockEnd then
if currentHHmm >= blockStart and currentHHmm < blockEnd then
return getResult("TIME_BLOCK", currentMonthly, false)
return getResult('TIME_BLOCK', currentMonthly, false)
end
elseif blockStart > blockEnd then
if currentHHmm >= blockStart or currentHHmm < blockEnd then
return getResult("TIME_BLOCK", currentMonthly, false)
return getResult('TIME_BLOCK', currentMonthly, false)
end
else
return getResult("TIME_BLOCK", currentMonthly, false)
return getResult('TIME_BLOCK', currentMonthly, false)
end
end

if monthlyLimit ~= -1 then
if (currentMonthly + usageBytes) > monthlyLimit then
return getResult("MONTHLY_LIMIT_EXCEEDED", currentMonthly, false)
return getResult('MONTHLY_LIMIT_EXCEEDED', currentMonthly, false)
end
end

Expand All @@ -105,53 +108,51 @@ if currentRemaining == nil then
end

if currentRemaining < usageBytes then
return getResult("FAMILY_QUOTA_EXCEEDED", currentMonthly, false)
return getResult('FAMILY_QUOTA_EXCEEDED', currentMonthly, false)
end

-- 4. 사용량 반영
-- 4) 사용량 반영
local newRemaining = redis.call('DECRBY', KEYS[2], usageBytes)
local newMonthly = redis.call('INCRBY', KEYS[3], usageBytes)

-- 5. 경고 상태 계산
-- 5) 후속 상태 계산
local limitStr = redis.call('HGET', KEYS[1], 'totalQuota')
local totalLimit = tonumber(limitStr or '0')
local status = "NORMAL"
local status = 'NORMAL'
local ratio = 0

if newRemaining <= 0 then
status = "FAMILY_QUOTA_EXCEEDED"
else
local ratio = 0
if totalLimit > 0 then
ratio = newRemaining / totalLimit
end
if totalLimit > 0 then
ratio = newRemaining / totalLimit
end

local alertLevel = nil
if ratio < 0.1 then
alertLevel = "10"
status = "WARNING_10"
elseif ratio < 0.3 then
alertLevel = "30"
status = "WARNING_30"
elseif ratio < 0.5 then
alertLevel = "50"
status = "WARNING_50"
end
local alertLevel = nil
if ratio < 0.1 then
alertLevel = '10'
status = 'WARNING_10'
elseif ratio < 0.3 then
alertLevel = '30'
status = 'WARNING_30'
elseif ratio < 0.5 then
alertLevel = '50'
status = 'WARNING_50'
end
Comment thread
ChoiSeungeon marked this conversation as resolved.

-- 같은 임계치 알림은 한 번만 발행되게 보호
if alertLevel then
local alertKey = KEYS[5] .. ":" .. alertLevel
local isSent = redis.call('EXISTS', alertKey)
-- 같은 임계치 알림은 한 번만 발행
if alertLevel then
local alertKey = KEYS[5] .. ':' .. alertLevel
local isSent = redis.call('EXISTS', alertKey)

if isSent == 1 then
status = "NORMAL"
else
redis.call('SET', alertKey, "PUBLISHED")
end
if isSent == 1 then
status = 'NORMAL'
else
redis.call('SET', alertKey, 'PUBLISHED')
end
end

local totalUsed = totalLimit - newRemaining
local userRatio = 0
if totalLimit > 0 then userRatio = newMonthly / totalLimit end
if totalLimit > 0 then
userRatio = newMonthly / totalLimit
end

return {totalUsed, newRemaining, status, newMonthly, userRatio, monthlyLimit, 0}
Loading