Files
claude-relay-service/config/config.example.js
QTom 3b9c96dff8 feat(queue): 优化用户消息队列锁释放时机
将队列锁释放时机从"请求完成后"提前到"请求发送后",因为 Claude API
限流(RPM)基于请求发送时刻计算,无需等待响应完成。

主要变更:
- 移除锁续租机制(startLockRenewal、refreshUserMessageLock)
- 所有 relay 服务在请求发送成功后立即释放锁
- 流式请求通过 onResponseStart 回调在收到响应头时释放
- 调整默认配置:timeoutMs 60s→5s,lockTtlMs 120s→5s
- 新增 USER_MESSAGE_QUEUE_LOCK_TTL_MS 环境变量支持
2025-12-10 01:26:00 +08:00

219 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const path = require('path')
require('dotenv').config()
const config = {
// 🌐 服务器配置
server: {
port: parseInt(process.env.PORT) || 3000,
host: process.env.HOST || '0.0.0.0',
nodeEnv: process.env.NODE_ENV || 'development',
trustProxy: process.env.TRUST_PROXY === 'true'
},
// 🔐 安全配置
security: {
jwtSecret: process.env.JWT_SECRET || 'CHANGE-THIS-JWT-SECRET-IN-PRODUCTION',
adminSessionTimeout: parseInt(process.env.ADMIN_SESSION_TIMEOUT) || 86400000, // 24小时
apiKeyPrefix: process.env.API_KEY_PREFIX || 'cr_',
encryptionKey: process.env.ENCRYPTION_KEY || 'CHANGE-THIS-32-CHARACTER-KEY-NOW'
},
// 📊 Redis配置
redis: {
host: process.env.REDIS_HOST || '127.0.0.1',
port: parseInt(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD || '',
db: parseInt(process.env.REDIS_DB) || 0,
connectTimeout: 10000,
commandTimeout: 5000,
retryDelayOnFailover: 100,
maxRetriesPerRequest: 3,
lazyConnect: true,
enableTLS: process.env.REDIS_ENABLE_TLS === 'true'
},
// 🔗 会话管理配置
session: {
// 粘性会话TTL配置小时默认1小时
stickyTtlHours: parseFloat(process.env.STICKY_SESSION_TTL_HOURS) || 1,
// 续期阈值分钟默认0分钟不续期
renewalThresholdMinutes: parseInt(process.env.STICKY_SESSION_RENEWAL_THRESHOLD_MINUTES) || 0
},
// 🎯 Claude API配置
claude: {
apiUrl: process.env.CLAUDE_API_URL || 'https://api.anthropic.com/v1/messages',
apiVersion: process.env.CLAUDE_API_VERSION || '2023-06-01',
betaHeader:
process.env.CLAUDE_BETA_HEADER ||
'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14',
overloadHandling: {
enabled: (() => {
const minutes = parseInt(process.env.CLAUDE_OVERLOAD_HANDLING_MINUTES) || 0
// 验证配置值限制在0-1440分钟(24小时)内
return Math.max(0, Math.min(minutes, 1440))
})()
}
},
// ☁️ Bedrock API配置
bedrock: {
enabled: process.env.CLAUDE_CODE_USE_BEDROCK === '1',
defaultRegion: process.env.AWS_REGION || 'us-east-1',
smallFastModelRegion: process.env.ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION,
defaultModel: process.env.ANTHROPIC_MODEL || 'us.anthropic.claude-sonnet-4-20250514-v1:0',
smallFastModel:
process.env.ANTHROPIC_SMALL_FAST_MODEL || 'us.anthropic.claude-3-5-haiku-20241022-v1:0',
maxOutputTokens: parseInt(process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS) || 4096,
maxThinkingTokens: parseInt(process.env.MAX_THINKING_TOKENS) || 1024,
enablePromptCaching: process.env.DISABLE_PROMPT_CACHING !== '1'
},
// 🌐 代理配置
proxy: {
timeout: parseInt(process.env.DEFAULT_PROXY_TIMEOUT) || 600000, // 10分钟
maxRetries: parseInt(process.env.MAX_PROXY_RETRIES) || 3,
// 连接池与 Keep-Alive 配置(默认关闭,需要显式开启)
keepAlive: (() => {
if (process.env.PROXY_KEEP_ALIVE === undefined || process.env.PROXY_KEEP_ALIVE === '') {
return false
}
return process.env.PROXY_KEEP_ALIVE === 'true'
})(),
maxSockets: (() => {
if (process.env.PROXY_MAX_SOCKETS === undefined || process.env.PROXY_MAX_SOCKETS === '') {
return undefined
}
const parsed = parseInt(process.env.PROXY_MAX_SOCKETS)
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined
})(),
maxFreeSockets: (() => {
if (
process.env.PROXY_MAX_FREE_SOCKETS === undefined ||
process.env.PROXY_MAX_FREE_SOCKETS === ''
) {
return undefined
}
const parsed = parseInt(process.env.PROXY_MAX_FREE_SOCKETS)
return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined
})(),
// IP协议族配置true=IPv4, false=IPv6, 默认IPv4兼容性更好
useIPv4: process.env.PROXY_USE_IPV4 !== 'false' // 默认 true只有明确设置为 'false' 才使用 IPv6
},
// ⏱️ 请求超时配置
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT) || 600000, // 默认 10 分钟
// 📈 使用限制
limits: {
defaultTokenLimit: parseInt(process.env.DEFAULT_TOKEN_LIMIT) || 1000000
},
// 📝 日志配置
logging: {
level: process.env.LOG_LEVEL || 'info',
dirname: path.join(__dirname, '..', 'logs'),
maxSize: process.env.LOG_MAX_SIZE || '10m',
maxFiles: parseInt(process.env.LOG_MAX_FILES) || 5
},
// 🔧 系统配置
system: {
cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL) || 3600000, // 1小时
tokenUsageRetention: parseInt(process.env.TOKEN_USAGE_RETENTION) || 2592000000, // 30天
healthCheckInterval: parseInt(process.env.HEALTH_CHECK_INTERVAL) || 60000, // 1分钟
timezone: process.env.SYSTEM_TIMEZONE || 'Asia/Shanghai', // 默认UTC+8中国时区
timezoneOffset: parseInt(process.env.TIMEZONE_OFFSET) || 8 // UTC偏移小时数默认+8
},
// 🎨 Web界面配置
web: {
title: process.env.WEB_TITLE || 'Claude Relay Service',
description:
process.env.WEB_DESCRIPTION ||
'Multi-account Claude API relay service with beautiful management interface',
logoUrl: process.env.WEB_LOGO_URL || '/assets/logo.png',
enableCors: process.env.ENABLE_CORS === 'true',
sessionSecret: process.env.WEB_SESSION_SECRET || 'CHANGE-THIS-SESSION-SECRET'
},
// 🔐 LDAP 认证配置
ldap: {
enabled: process.env.LDAP_ENABLED === 'true',
server: {
url: process.env.LDAP_URL || 'ldap://localhost:389',
bindDN: process.env.LDAP_BIND_DN || 'cn=admin,dc=example,dc=com',
bindCredentials: process.env.LDAP_BIND_PASSWORD || 'admin',
searchBase: process.env.LDAP_SEARCH_BASE || 'dc=example,dc=com',
searchFilter: process.env.LDAP_SEARCH_FILTER || '(uid={{username}})',
searchAttributes: process.env.LDAP_SEARCH_ATTRIBUTES
? process.env.LDAP_SEARCH_ATTRIBUTES.split(',')
: ['dn', 'uid', 'cn', 'mail', 'givenName', 'sn'],
timeout: parseInt(process.env.LDAP_TIMEOUT) || 5000,
connectTimeout: parseInt(process.env.LDAP_CONNECT_TIMEOUT) || 10000,
// TLS/SSL 配置
tls: {
// 是否忽略证书错误 (用于自签名证书)
rejectUnauthorized: process.env.LDAP_TLS_REJECT_UNAUTHORIZED !== 'false', // 默认验证证书设置为false则忽略
// CA证书文件路径 (可选用于自定义CA证书)
ca: process.env.LDAP_TLS_CA_FILE
? require('fs').readFileSync(process.env.LDAP_TLS_CA_FILE)
: undefined,
// 客户端证书文件路径 (可选,用于双向认证)
cert: process.env.LDAP_TLS_CERT_FILE
? require('fs').readFileSync(process.env.LDAP_TLS_CERT_FILE)
: undefined,
// 客户端私钥文件路径 (可选,用于双向认证)
key: process.env.LDAP_TLS_KEY_FILE
? require('fs').readFileSync(process.env.LDAP_TLS_KEY_FILE)
: undefined,
// 服务器名称 (用于SNI可选)
servername: process.env.LDAP_TLS_SERVERNAME || undefined
}
},
userMapping: {
username: process.env.LDAP_USER_ATTR_USERNAME || 'uid',
displayName: process.env.LDAP_USER_ATTR_DISPLAY_NAME || 'cn',
email: process.env.LDAP_USER_ATTR_EMAIL || 'mail',
firstName: process.env.LDAP_USER_ATTR_FIRST_NAME || 'givenName',
lastName: process.env.LDAP_USER_ATTR_LAST_NAME || 'sn'
}
},
// 👥 用户管理配置
userManagement: {
enabled: process.env.USER_MANAGEMENT_ENABLED === 'true',
defaultUserRole: process.env.DEFAULT_USER_ROLE || 'user',
userSessionTimeout: parseInt(process.env.USER_SESSION_TIMEOUT) || 86400000, // 24小时
maxApiKeysPerUser: parseInt(process.env.MAX_API_KEYS_PER_USER) || 1,
allowUserDeleteApiKeys: process.env.ALLOW_USER_DELETE_API_KEYS === 'true' // 默认不允许用户删除自己的API Keys
},
// 📢 Webhook通知配置
webhook: {
enabled: process.env.WEBHOOK_ENABLED !== 'false', // 默认启用
urls: process.env.WEBHOOK_URLS
? process.env.WEBHOOK_URLS.split(',').map((url) => url.trim())
: [],
timeout: parseInt(process.env.WEBHOOK_TIMEOUT) || 10000, // 10秒超时
retries: parseInt(process.env.WEBHOOK_RETRIES) || 3 // 重试3次
},
// 🛠️ 开发配置
development: {
debug: process.env.DEBUG === 'true',
hotReload: process.env.HOT_RELOAD === 'true'
},
// 📬 用户消息队列配置
// 优化说明:锁在请求发送成功后立即释放(而非请求完成后),因为 Claude API 限流基于请求发送时刻计算
userMessageQueue: {
enabled: process.env.USER_MESSAGE_QUEUE_ENABLED === 'true', // 默认关闭
delayMs: parseInt(process.env.USER_MESSAGE_QUEUE_DELAY_MS) || 200, // 请求间隔(毫秒)
timeoutMs: parseInt(process.env.USER_MESSAGE_QUEUE_TIMEOUT_MS) || 5000, // 队列等待超时(毫秒),锁持有时间短,无需长等待
lockTtlMs: parseInt(process.env.USER_MESSAGE_QUEUE_LOCK_TTL_MS) || 5000 // 锁TTL毫秒5秒足以覆盖请求发送
}
}
module.exports = config