Merge pull request #808 from SilentFlower/fix/openai-scheduler-priority [skip ci]

fix(scheduler): 恢复OpenAI 账号选择支持 priority + lastUsedAt
This commit is contained in:
Wesley Liddick
2025-12-16 19:33:18 -05:00
committed by GitHub

View File

@@ -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)