feat(concurrencyManagement): implement concurrency status management API and enhance concurrency handling in middleware

This commit is contained in:
DaydreamCoding
2025-12-06 17:23:42 +08:00
committed by QTom
parent d81a16b98d
commit f74f77ef65
4 changed files with 430 additions and 2 deletions

View File

@@ -0,0 +1,145 @@
/**
* 并发管理 API 路由
* 提供并发状态查看和手动清理功能
*/
const express = require('express')
const router = express.Router()
const redis = require('../../models/redis')
const logger = require('../../utils/logger')
/**
* GET /admin/concurrency
* 获取所有并发状态
*/
router.get('/concurrency', async (req, res) => {
try {
const status = await redis.getAllConcurrencyStatus()
// 计算汇总统计
const summary = {
totalKeys: status.length,
totalActiveRequests: status.reduce((sum, s) => sum + s.activeCount, 0),
totalExpiredRequests: status.reduce((sum, s) => sum + s.expiredCount, 0)
}
res.json({
success: true,
summary,
concurrencyStatus: status
})
} catch (error) {
logger.error('❌ Failed to get concurrency status:', error)
res.status(500).json({
success: false,
error: 'Failed to get concurrency status',
message: error.message
})
}
})
/**
* GET /admin/concurrency/:apiKeyId
* 获取特定 API Key 的并发状态详情
*/
router.get('/concurrency/:apiKeyId', async (req, res) => {
try {
const { apiKeyId } = req.params
const status = await redis.getConcurrencyStatus(apiKeyId)
res.json({
success: true,
concurrencyStatus: status
})
} catch (error) {
logger.error(`❌ Failed to get concurrency status for ${req.params.apiKeyId}:`, error)
res.status(500).json({
success: false,
error: 'Failed to get concurrency status',
message: error.message
})
}
})
/**
* DELETE /admin/concurrency/:apiKeyId
* 强制清理特定 API Key 的并发计数
*/
router.delete('/concurrency/:apiKeyId', async (req, res) => {
try {
const { apiKeyId } = req.params
const result = await redis.forceClearConcurrency(apiKeyId)
logger.warn(
`🧹 Admin ${req.admin?.username || 'unknown'} force cleared concurrency for key ${apiKeyId}`
)
res.json({
success: true,
message: `Successfully cleared concurrency for API key ${apiKeyId}`,
result
})
} catch (error) {
logger.error(`❌ Failed to clear concurrency for ${req.params.apiKeyId}:`, error)
res.status(500).json({
success: false,
error: 'Failed to clear concurrency',
message: error.message
})
}
})
/**
* DELETE /admin/concurrency
* 强制清理所有并发计数
*/
router.delete('/concurrency', async (req, res) => {
try {
const result = await redis.forceClearAllConcurrency()
logger.warn(`🧹 Admin ${req.admin?.username || 'unknown'} force cleared ALL concurrency`)
res.json({
success: true,
message: 'Successfully cleared all concurrency',
result
})
} catch (error) {
logger.error('❌ Failed to clear all concurrency:', error)
res.status(500).json({
success: false,
error: 'Failed to clear all concurrency',
message: error.message
})
}
})
/**
* POST /admin/concurrency/cleanup
* 清理过期的并发条目(不影响活跃请求)
*/
router.post('/concurrency/cleanup', async (req, res) => {
try {
const { apiKeyId } = req.body
const result = await redis.cleanupExpiredConcurrency(apiKeyId || null)
logger.info(`🧹 Admin ${req.admin?.username || 'unknown'} cleaned up expired concurrency`)
res.json({
success: true,
message: apiKeyId
? `Successfully cleaned up expired concurrency for API key ${apiKeyId}`
: 'Successfully cleaned up all expired concurrency',
result
})
} catch (error) {
logger.error('❌ Failed to cleanup expired concurrency:', error)
res.status(500).json({
success: false,
error: 'Failed to cleanup expired concurrency',
message: error.message
})
}
})
module.exports = router

View File

@@ -22,6 +22,7 @@ const droidAccountsRoutes = require('./droidAccounts')
const dashboardRoutes = require('./dashboard')
const usageStatsRoutes = require('./usageStats')
const systemRoutes = require('./system')
const concurrencyRoutes = require('./concurrency')
// 挂载所有子路由
// 使用完整路径的模块(直接挂载到根路径)
@@ -35,6 +36,7 @@ router.use('/', droidAccountsRoutes)
router.use('/', dashboardRoutes)
router.use('/', usageStatsRoutes)
router.use('/', systemRoutes)
router.use('/', concurrencyRoutes)
// 使用相对路径的模块(需要指定基础路径前缀)
router.use('/account-groups', accountGroupsRoutes)