fix: 修复并发计数器在请求异常时不能正确减少的问题

- 增强事件监听机制
  - 监听 req 的 close 和 aborted 事件
  - 监听 res 的 finish 和 error 事件
  - 使用标志位确保只减少一次计数

- 改进日志记录
  - 增加并发计数增减的详细日志
  - 记录请求关闭和中断事件

- 确保计数器安全性
  - 使用 Lua 脚本原子操作防止负数
  - 优化 Redis 操作逻辑

- 增强管理界面
  - API Keys 列表显示当前并发数
  - 并发数超过 0 时用橙色标记
  - 显示当前并发数/限制数格式

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-16 10:21:17 +08:00
parent e2c9f26135
commit 08f93e9872
4 changed files with 62 additions and 18 deletions

View File

@@ -65,6 +65,7 @@ const authenticateApiKey = async (req, res, next) => {
const concurrencyLimit = validation.keyData.concurrencyLimit || 0;
if (concurrencyLimit > 0) {
const currentConcurrency = await redis.incrConcurrency(validation.keyData.id);
logger.api(`📈 Incremented concurrency for key: ${validation.keyData.id} (${validation.keyData.name}), current: ${currentConcurrency}, limit: ${concurrencyLimit}`);
if (currentConcurrency > concurrencyLimit) {
// 如果超过限制,立即减少计数
@@ -78,19 +79,38 @@ const authenticateApiKey = async (req, res, next) => {
});
}
// 在响应结束时减少并发计数
res.on('finish', () => {
redis.decrConcurrency(validation.keyData.id).catch(error => {
logger.error('Failed to decrement concurrency:', error);
});
// 使用标志位确保只减少一次
let concurrencyDecremented = false;
const decrementConcurrency = async () => {
if (!concurrencyDecremented) {
concurrencyDecremented = true;
try {
const newCount = await redis.decrConcurrency(validation.keyData.id);
logger.api(`📉 Decremented concurrency for key: ${validation.keyData.id} (${validation.keyData.name}), new count: ${newCount}`);
} catch (error) {
logger.error(`Failed to decrement concurrency for key ${validation.keyData.id}:`, error);
}
}
};
// 监听多个事件以确保在各种情况下都能正确减少计数
res.on('finish', decrementConcurrency);
res.on('error', decrementConcurrency);
req.on('close', () => {
logger.api(`🔌 Request closed for key: ${validation.keyData.id} (${validation.keyData.name})`);
decrementConcurrency();
});
req.on('aborted', () => {
logger.api(`⚠️ Request aborted for key: ${validation.keyData.id} (${validation.keyData.name})`);
decrementConcurrency();
});
// 在响应错误时也减少并发计数
res.on('error', () => {
redis.decrConcurrency(validation.keyData.id).catch(error => {
logger.error('Failed to decrement concurrency on error:', error);
});
});
// 存储并发信息到请求对象,便于后续处理
req.concurrencyInfo = {
apiKeyId: validation.keyData.id,
decrementConcurrency
};
}
// 将验证信息添加到请求对象(只包含必要信息)