mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
Merge pull request #808 from SilentFlower/fix/openai-scheduler-priority [skip ci]
fix(scheduler): 恢复OpenAI 账号选择支持 priority + lastUsedAt
This commit is contained in:
@@ -9,6 +9,26 @@ class UnifiedOpenAIScheduler {
|
|||||||
this.SESSION_MAPPING_PREFIX = 'unified_openai_session_mapping:'
|
this.SESSION_MAPPING_PREFIX = 'unified_openai_session_mapping:'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔢 按优先级和最后使用时间排序账户(与 Claude/Gemini 调度保持一致)
|
||||||
|
_sortAccountsByPriority(accounts) {
|
||||||
|
return accounts.sort((a, b) => {
|
||||||
|
const aPriority = Number.parseInt(a.priority, 10)
|
||||||
|
const bPriority = Number.parseInt(b.priority, 10)
|
||||||
|
const normalizedAPriority = Number.isFinite(aPriority) ? aPriority : 50
|
||||||
|
const normalizedBPriority = Number.isFinite(bPriority) ? bPriority : 50
|
||||||
|
|
||||||
|
// 首先按优先级排序(数字越小优先级越高)
|
||||||
|
if (normalizedAPriority !== normalizedBPriority) {
|
||||||
|
return normalizedAPriority - normalizedBPriority
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先级相同时,按最后使用时间排序(最久未使用的优先)
|
||||||
|
const aLastUsed = new Date(a.lastUsedAt || 0).getTime()
|
||||||
|
const bLastUsed = new Date(b.lastUsedAt || 0).getTime()
|
||||||
|
return aLastUsed - bLastUsed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 🔧 辅助方法:检查账户是否可调度(兼容字符串和布尔值)
|
// 🔧 辅助方法:检查账户是否可调度(兼容字符串和布尔值)
|
||||||
_isSchedulable(schedulable) {
|
_isSchedulable(schedulable) {
|
||||||
// 如果是 undefined 或 null,默认为可调度
|
// 如果是 undefined 或 null,默认为可调度
|
||||||
@@ -244,13 +264,7 @@ class UnifiedOpenAIScheduler {
|
|||||||
`🎯 Using bound dedicated ${accountType} account: ${boundAccount.name} (${boundAccount.id}) for API key ${apiKeyData.name}`
|
`🎯 Using bound dedicated ${accountType} account: ${boundAccount.name} (${boundAccount.id}) for API key ${apiKeyData.name}`
|
||||||
)
|
)
|
||||||
// 更新账户的最后使用时间
|
// 更新账户的最后使用时间
|
||||||
if (accountType === 'openai') {
|
await this.updateAccountLastUsed(boundAccount.id, accountType)
|
||||||
await openaiAccountService.recordUsage(boundAccount.id, 0)
|
|
||||||
} else {
|
|
||||||
await openaiResponsesAccountService.updateAccount(boundAccount.id, {
|
|
||||||
lastUsedAt: new Date().toISOString()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
accountId: boundAccount.id,
|
accountId: boundAccount.id,
|
||||||
accountType
|
accountType
|
||||||
@@ -292,7 +306,7 @@ class UnifiedOpenAIScheduler {
|
|||||||
`🎯 Using sticky session account: ${mappedAccount.accountId} (${mappedAccount.accountType}) for session ${sessionHash}`
|
`🎯 Using sticky session account: ${mappedAccount.accountId} (${mappedAccount.accountType}) for session ${sessionHash}`
|
||||||
)
|
)
|
||||||
// 更新账户的最后使用时间
|
// 更新账户的最后使用时间
|
||||||
await openaiAccountService.recordUsage(mappedAccount.accountId, 0)
|
await this.updateAccountLastUsed(mappedAccount.accountId, mappedAccount.accountType)
|
||||||
return mappedAccount
|
return mappedAccount
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
@@ -321,12 +335,8 @@ class UnifiedOpenAIScheduler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按最后使用时间排序(最久未使用的优先,与 Claude 保持一致)
|
// 按优先级和最后使用时间排序(与 Claude/Gemini 调度保持一致)
|
||||||
const sortedAccounts = availableAccounts.sort((a, b) => {
|
const sortedAccounts = this._sortAccountsByPriority(availableAccounts)
|
||||||
const aLastUsed = new Date(a.lastUsedAt || 0).getTime()
|
|
||||||
const bLastUsed = new Date(b.lastUsedAt || 0).getTime()
|
|
||||||
return aLastUsed - bLastUsed // 最久未使用的优先
|
|
||||||
})
|
|
||||||
|
|
||||||
// 选择第一个账户
|
// 选择第一个账户
|
||||||
const selectedAccount = sortedAccounts[0]
|
const selectedAccount = sortedAccounts[0]
|
||||||
@@ -344,11 +354,11 @@ class UnifiedOpenAIScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`🎯 Selected account: ${selectedAccount.name} (${selectedAccount.accountId}, ${selectedAccount.accountType}) for API key ${apiKeyData.name}`
|
`🎯 Selected account: ${selectedAccount.name} (${selectedAccount.accountId}, ${selectedAccount.accountType}, priority: ${selectedAccount.priority || 50}) for API key ${apiKeyData.name}`
|
||||||
)
|
)
|
||||||
|
|
||||||
// 更新账户的最后使用时间
|
// 更新账户的最后使用时间
|
||||||
await openaiAccountService.recordUsage(selectedAccount.accountId, 0)
|
await this.updateAccountLastUsed(selectedAccount.accountId, selectedAccount.accountType)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accountId: selectedAccount.accountId,
|
accountId: selectedAccount.accountId,
|
||||||
@@ -494,21 +504,6 @@ class UnifiedOpenAIScheduler {
|
|||||||
return availableAccounts
|
return availableAccounts
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔢 按优先级和最后使用时间排序账户(已废弃,改为与 Claude 保持一致,只按最后使用时间排序)
|
|
||||||
// _sortAccountsByPriority(accounts) {
|
|
||||||
// return accounts.sort((a, b) => {
|
|
||||||
// // 首先按优先级排序(数字越小优先级越高)
|
|
||||||
// if (a.priority !== b.priority) {
|
|
||||||
// return a.priority - b.priority
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 优先级相同时,按最后使用时间排序(最久未使用的优先)
|
|
||||||
// const aLastUsed = new Date(a.lastUsedAt || 0).getTime()
|
|
||||||
// const bLastUsed = new Date(b.lastUsedAt || 0).getTime()
|
|
||||||
// return aLastUsed - bLastUsed
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 🔍 检查账户是否可用
|
// 🔍 检查账户是否可用
|
||||||
async _isAccountAvailable(accountId, accountType) {
|
async _isAccountAvailable(accountId, accountType) {
|
||||||
try {
|
try {
|
||||||
@@ -817,7 +812,7 @@ class UnifiedOpenAIScheduler {
|
|||||||
`🎯 Using sticky session account from group: ${mappedAccount.accountId} (${mappedAccount.accountType})`
|
`🎯 Using sticky session account from group: ${mappedAccount.accountId} (${mappedAccount.accountType})`
|
||||||
)
|
)
|
||||||
// 更新账户的最后使用时间
|
// 更新账户的最后使用时间
|
||||||
await openaiAccountService.recordUsage(mappedAccount.accountId, 0)
|
await this.updateAccountLastUsed(mappedAccount.accountId, mappedAccount.accountType)
|
||||||
return mappedAccount
|
return mappedAccount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -909,12 +904,8 @@ class UnifiedOpenAIScheduler {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按最后使用时间排序(最久未使用的优先,与 Claude 保持一致)
|
// 按优先级和最后使用时间排序(与 Claude/Gemini 调度保持一致)
|
||||||
const sortedAccounts = availableAccounts.sort((a, b) => {
|
const sortedAccounts = this._sortAccountsByPriority(availableAccounts)
|
||||||
const aLastUsed = new Date(a.lastUsedAt || 0).getTime()
|
|
||||||
const bLastUsed = new Date(b.lastUsedAt || 0).getTime()
|
|
||||||
return aLastUsed - bLastUsed // 最久未使用的优先
|
|
||||||
})
|
|
||||||
|
|
||||||
// 选择第一个账户
|
// 选择第一个账户
|
||||||
const selectedAccount = sortedAccounts[0]
|
const selectedAccount = sortedAccounts[0]
|
||||||
@@ -932,11 +923,11 @@ class UnifiedOpenAIScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
`🎯 Selected account from group: ${selectedAccount.name} (${selectedAccount.accountId})`
|
`🎯 Selected account from group: ${selectedAccount.name} (${selectedAccount.accountId}, ${selectedAccount.accountType}, priority: ${selectedAccount.priority || 50})`
|
||||||
)
|
)
|
||||||
|
|
||||||
// 更新账户的最后使用时间
|
// 更新账户的最后使用时间
|
||||||
await openaiAccountService.recordUsage(selectedAccount.accountId, 0)
|
await this.updateAccountLastUsed(selectedAccount.accountId, selectedAccount.accountType)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accountId: selectedAccount.accountId,
|
accountId: selectedAccount.accountId,
|
||||||
@@ -958,9 +949,12 @@ class UnifiedOpenAIScheduler {
|
|||||||
async updateAccountLastUsed(accountId, accountType) {
|
async updateAccountLastUsed(accountId, accountType) {
|
||||||
try {
|
try {
|
||||||
if (accountType === 'openai') {
|
if (accountType === 'openai') {
|
||||||
await openaiAccountService.updateAccount(accountId, {
|
await openaiAccountService.recordUsage(accountId, 0)
|
||||||
lastUsedAt: new Date().toISOString()
|
return
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if (accountType === 'openai-responses') {
|
||||||
|
await openaiResponsesAccountService.recordUsage(accountId, 0)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(`⚠️ Failed to update last used time for account ${accountId}:`, error)
|
logger.warn(`⚠️ Failed to update last used time for account ${accountId}:`, error)
|
||||||
|
|||||||
Reference in New Issue
Block a user