From a2b04eea07c29e7ec153219be12bc0cf012d5b23 Mon Sep 17 00:00:00 2001 From: shaw Date: Thu, 30 Oct 2025 15:59:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=80=BB=E8=B4=B9?= =?UTF-8?q?=E7=94=A8=E8=A2=AB=E9=87=8D=E7=BD=AE=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/redis.js | 6 +++--- src/services/costInitService.js | 28 ++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/models/redis.js b/src/models/redis.js index 4f222f64..e81c89ce 100644 --- a/src/models/redis.js +++ b/src/models/redis.js @@ -714,7 +714,7 @@ class RedisClient { const dailyKey = `usage:cost:daily:${keyId}:${today}` const monthlyKey = `usage:cost:monthly:${keyId}:${currentMonth}` const hourlyKey = `usage:cost:hourly:${keyId}:${currentHour}` - const totalKey = `usage:cost:total:${keyId}` + const totalKey = `usage:cost:total:${keyId}` // 总费用键 - 永不过期,持续累加 logger.debug( `💰 Incrementing cost for ${keyId}, amount: $${amount}, date: ${today}, dailyKey: ${dailyKey}` @@ -724,8 +724,8 @@ class RedisClient { this.client.incrbyfloat(dailyKey, amount), this.client.incrbyfloat(monthlyKey, amount), this.client.incrbyfloat(hourlyKey, amount), - this.client.incrbyfloat(totalKey, amount), - // 设置过期时间 + this.client.incrbyfloat(totalKey, amount), // ✅ 累加到总费用(永不过期) + // 设置过期时间(注意:totalKey 不设置过期时间,保持永久累计) this.client.expire(dailyKey, 86400 * 30), // 30天 this.client.expire(monthlyKey, 86400 * 90), // 90天 this.client.expire(hourlyKey, 86400 * 7) // 7天 diff --git a/src/services/costInitService.js b/src/services/costInitService.js index ead54d46..1edd65b1 100644 --- a/src/services/costInitService.js +++ b/src/services/costInitService.js @@ -133,10 +133,34 @@ class CostInitService { totalCost += cost } - // 写入总费用 + // 写入总费用 - 修复:只在总费用不存在时初始化,避免覆盖现有累计值 if (totalCost > 0) { const totalKey = `usage:cost:total:${apiKeyId}` - promises.push(client.set(totalKey, totalCost.toString())) + // 先检查总费用是否已存在 + const existingTotal = await client.get(totalKey) + + if (!existingTotal || parseFloat(existingTotal) === 0) { + // 仅在总费用不存在或为0时才初始化 + promises.push(client.set(totalKey, totalCost.toString())) + logger.info(`💰 Initialized total cost for API Key ${apiKeyId}: $${totalCost.toFixed(6)}`) + } else { + // 如果总费用已存在,保持不变,避免覆盖累计值 + // 注意:这个逻辑防止因每日费用键过期(30天)导致的错误覆盖 + // 如果需要强制重新计算,请先手动删除 usage:cost:total:{keyId} 键 + const existing = parseFloat(existingTotal) + const calculated = totalCost + + if (calculated > existing * 1.1) { + // 如果计算值比现有值大 10% 以上,记录警告(可能是数据不一致) + logger.warn( + `💰 Total cost mismatch for API Key ${apiKeyId}: existing=$${existing.toFixed(6)}, calculated=$${calculated.toFixed(6)} (from last 30 days). Keeping existing value to prevent data loss.` + ) + } else { + logger.debug( + `💰 Skipping total cost initialization for API Key ${apiKeyId} - existing: $${existing.toFixed(6)}, calculated: $${calculated.toFixed(6)}` + ) + } + } } await Promise.all(promises)