Fix/api key concurrency runtime miss (#309)

* test(cli): 覆盖 API key 并发等待与超时路径

* feat(scheduler): API key 并发饱和时等待可用槽位

* fix(proxy): 区分 API key 并发受限与真正的 runtime miss

* fix(outcome): runtime miss 仅归因真实执行候选

* feat(api-keys): 统一 concurrent_limit 默认值与校验辅助

* feat(admin): 独立 Key 接口支持 concurrent_limit

* feat(admin): 用户 API Key 路由支持 concurrent_limit

* feat(public): 自助 API Key 路由支持 concurrent_limit

* feat(import): 导入与存储层持久化 concurrent_limit

* feat(frontend): 同步 API Key concurrent_limit 类型定义

* feat(frontend): 独立 Key 表单支持 concurrent_limit

* feat(frontend): 管理员用户 API Key 表单支持 concurrent_limit

* feat(frontend): 自助 API Key 页面支持 concurrent_limit

* chore(fmt): 统一 runtime 归因相关 Rust 格式

* chore(fmt): 统一 admin API key 路由 Rust 格式

* chore(fmt): 统一 public 路由与相关测试 Rust 格式

* fix(test): 对齐 no-execution usage 归因断言

* test(middleware): 固定 access log tracing 用例线程模型

* fix(frontend): 提取用户 API Key payload 默认并发辅助

* fix(frontend): 保留用户 Key 的 concurrent_limit 默认值

* fix(api-keys): remove hardcoded concurrent limit default

---------

Co-authored-by: fawney19 <[email protected]>
This commit is contained in:
RWDai
2026-04-17 14:21:43 +08:00
committed by GitHub
co-authored by fawney19
parent e5d3722adf
commit b8702ae124
39 changed files with 1739 additions and 128 deletions
+6 -3
View File
@@ -1,4 +1,5 @@
import apiClient from './client'
import type { UserSession as SessionRecord } from '@/types/session'
export interface User {
id: string // UUID
@@ -53,6 +54,7 @@ export interface ApiKey {
is_locked: boolean // 管理员锁定标志
is_standalone: boolean // 是否为独立余额Key
rate_limit?: number | null // 普通Key: 0 = 不限制,历史 null 视为跟随系统默认
concurrent_limit?: number | null // 普通Key: 0 = 不限制并发,历史 null 兼容
total_requests?: number // 总请求数
total_cost_usd?: number // 总费用
}
@@ -60,9 +62,10 @@ export interface ApiKey {
export interface UpsertUserApiKeyRequest {
name?: string
rate_limit?: number | null
concurrent_limit?: number | null
}
export type { UserSession } from '@/types/session'
export type UserSession = SessionRecord
export const usersApi = {
async getAllUsers(): Promise<User[]> {
@@ -94,8 +97,8 @@ export const usersApi = {
return response.data.api_keys
},
async getUserSessions(userId: string): Promise<UserSession[]> {
const response = await apiClient.get<UserSession[]>(`/api/admin/users/${userId}/sessions`)
async getUserSessions(userId: string): Promise<SessionRecord[]> {
const response = await apiClient.get<SessionRecord[]>(`/api/admin/users/${userId}/sessions`)
return response.data
},