mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 优化粘性会话TTL管理策略
- 将TTL默认值从15天改为1小时,更适合短期会话场景 - 将续期阈值默认设为0,默认不自动续期,提高控制精度 - 时间单位从天调整为小时/分钟,提供更细粒度的控制 - 添加环境变量配置支持:STICKY_SESSION_TTL_HOURS 和 STICKY_SESSION_RENEWAL_THRESHOLD_MINUTES - 保持向后兼容性,所有现有部署将自动使用新的默认值 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,12 @@ REDIS_PASSWORD=
|
|||||||
REDIS_DB=0
|
REDIS_DB=0
|
||||||
REDIS_ENABLE_TLS=
|
REDIS_ENABLE_TLS=
|
||||||
|
|
||||||
|
# 🔗 会话管理配置
|
||||||
|
# 粘性会话TTL配置(小时),默认1小时
|
||||||
|
STICKY_SESSION_TTL_HOURS=1
|
||||||
|
# 续期阈值(分钟),默认0分钟(不续期)
|
||||||
|
STICKY_SESSION_RENEWAL_THRESHOLD_MINUTES=0
|
||||||
|
|
||||||
# 🎯 Claude API 配置
|
# 🎯 Claude API 配置
|
||||||
CLAUDE_API_URL=https://api.anthropic.com/v1/messages
|
CLAUDE_API_URL=https://api.anthropic.com/v1/messages
|
||||||
CLAUDE_API_VERSION=2023-06-01
|
CLAUDE_API_VERSION=2023-06-01
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ const config = {
|
|||||||
|
|
||||||
// 🔗 会话管理配置
|
// 🔗 会话管理配置
|
||||||
session: {
|
session: {
|
||||||
// 粘性会话TTL配置(天)
|
// 粘性会话TTL配置(小时),默认1小时
|
||||||
stickyTtlDays: parseInt(process.env.STICKY_SESSION_TTL_DAYS) || 15,
|
stickyTtlHours: parseFloat(process.env.STICKY_SESSION_TTL_HOURS) || 1,
|
||||||
// 续期阈值(天)
|
// 续期阈值(分钟),默认0分钟(不续期)
|
||||||
renewalThresholdDays: parseInt(process.env.STICKY_SESSION_RENEWAL_THRESHOLD_DAYS) || 14
|
renewalThresholdMinutes: parseInt(process.env.STICKY_SESSION_RENEWAL_THRESHOLD_MINUTES) || 0
|
||||||
},
|
},
|
||||||
|
|
||||||
// 🎯 Claude API配置
|
// 🎯 Claude API配置
|
||||||
|
|||||||
@@ -1358,7 +1358,8 @@ class RedisClient {
|
|||||||
// 🔗 会话sticky映射管理
|
// 🔗 会话sticky映射管理
|
||||||
async setSessionAccountMapping(sessionHash, accountId, ttl = null) {
|
async setSessionAccountMapping(sessionHash, accountId, ttl = null) {
|
||||||
const appConfig = require('../../config/config')
|
const appConfig = require('../../config/config')
|
||||||
const defaultTTL = ttl !== null ? ttl : (appConfig.session?.stickyTtlDays || 15) * 24 * 60 * 60
|
// 从配置读取TTL(小时),转换为秒,默认1小时
|
||||||
|
const defaultTTL = ttl !== null ? ttl : (appConfig.session?.stickyTtlHours || 1) * 60 * 60
|
||||||
const key = `sticky_session:${sessionHash}`
|
const key = `sticky_session:${sessionHash}`
|
||||||
await this.client.set(key, accountId, 'EX', defaultTTL)
|
await this.client.set(key, accountId, 'EX', defaultTTL)
|
||||||
}
|
}
|
||||||
@@ -1374,11 +1375,16 @@ class RedisClient {
|
|||||||
const key = `sticky_session:${sessionHash}`
|
const key = `sticky_session:${sessionHash}`
|
||||||
|
|
||||||
// 📊 从配置获取参数
|
// 📊 从配置获取参数
|
||||||
const ttlDays = appConfig.session?.stickyTtlDays || 15
|
const ttlHours = appConfig.session?.stickyTtlHours || 1 // 小时,默认1小时
|
||||||
const thresholdDays = appConfig.session?.renewalThresholdDays || 14
|
const thresholdMinutes = appConfig.session?.renewalThresholdMinutes || 0 // 分钟,默认0(不续期)
|
||||||
|
|
||||||
const fullTTL = ttlDays * 24 * 60 * 60 // 转换为秒
|
// 如果阈值为0,不执行续期
|
||||||
const renewalThreshold = thresholdDays * 24 * 60 * 60 // 转换为秒
|
if (thresholdMinutes === 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullTTL = ttlHours * 60 * 60 // 转换为秒
|
||||||
|
const renewalThreshold = thresholdMinutes * 60 // 转换为秒
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取当前剩余TTL(秒)
|
// 获取当前剩余TTL(秒)
|
||||||
@@ -1398,14 +1404,14 @@ class RedisClient {
|
|||||||
if (remainingTTL < renewalThreshold) {
|
if (remainingTTL < renewalThreshold) {
|
||||||
await this.client.expire(key, fullTTL)
|
await this.client.expire(key, fullTTL)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`🔄 Renewed sticky session TTL: ${sessionHash} (was ${Math.round(remainingTTL / 24 / 3600)}d, renewed to ${ttlDays}d)`
|
`🔄 Renewed sticky session TTL: ${sessionHash} (was ${Math.round(remainingTTL / 60)}min, renewed to ${ttlHours}h)`
|
||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 剩余时间充足,无需续期
|
// 剩余时间充足,无需续期
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`✅ Sticky session TTL sufficient: ${sessionHash} (remaining ${Math.round(remainingTTL / 24 / 3600)}d)`
|
`✅ Sticky session TTL sufficient: ${sessionHash} (remaining ${Math.round(remainingTTL / 60)}min)`
|
||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ const crypto = require('crypto')
|
|||||||
const ProxyHelper = require('../utils/proxyHelper')
|
const ProxyHelper = require('../utils/proxyHelper')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const redis = require('../models/redis')
|
const redis = require('../models/redis')
|
||||||
const logger = require('../utils/logger')
|
|
||||||
const config = require('../../config/config')
|
const config = require('../../config/config')
|
||||||
|
const logger = require('../utils/logger')
|
||||||
const { maskToken } = require('../utils/tokenMask')
|
const { maskToken } = require('../utils/tokenMask')
|
||||||
const {
|
const {
|
||||||
logRefreshStart,
|
logRefreshStart,
|
||||||
@@ -723,7 +723,9 @@ class ClaudeAccountService {
|
|||||||
|
|
||||||
// 如果有会话哈希,建立新的映射
|
// 如果有会话哈希,建立新的映射
|
||||||
if (sessionHash) {
|
if (sessionHash) {
|
||||||
await redis.setSessionAccountMapping(sessionHash, selectedAccountId, 3600) // 1小时过期
|
// 从配置获取TTL(小时),转换为秒
|
||||||
|
const ttlSeconds = (config.session?.stickyTtlHours || 1) * 60 * 60
|
||||||
|
await redis.setSessionAccountMapping(sessionHash, selectedAccountId, ttlSeconds)
|
||||||
logger.info(
|
logger.info(
|
||||||
`🎯 Created new sticky session mapping: ${sortedAccounts[0].name} (${selectedAccountId}) for session ${sessionHash}`
|
`🎯 Created new sticky session mapping: ${sortedAccounts[0].name} (${selectedAccountId}) for session ${sessionHash}`
|
||||||
)
|
)
|
||||||
@@ -877,7 +879,9 @@ class ClaudeAccountService {
|
|||||||
|
|
||||||
// 如果有会话哈希,建立新的映射
|
// 如果有会话哈希,建立新的映射
|
||||||
if (sessionHash) {
|
if (sessionHash) {
|
||||||
await redis.setSessionAccountMapping(sessionHash, selectedAccountId, 3600) // 1小时过期
|
// 从配置获取TTL(小时),转换为秒
|
||||||
|
const ttlSeconds = (config.session?.stickyTtlHours || 1) * 60 * 60
|
||||||
|
await redis.setSessionAccountMapping(sessionHash, selectedAccountId, ttlSeconds)
|
||||||
logger.info(
|
logger.info(
|
||||||
`🎯 Created new sticky session mapping for shared account: ${candidateAccounts[0].name} (${selectedAccountId}) for session ${sessionHash}`
|
`🎯 Created new sticky session mapping for shared account: ${candidateAccounts[0].name} (${selectedAccountId}) for session ${sessionHash}`
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user