mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
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 <elky0401@gmail.com>
This commit is contained in:
@@ -174,6 +174,12 @@
|
||||
>
|
||||
{{ formatRateLimitSimple(apiKey.rate_limit) }}
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
class="h-5 px-2 py-0 text-[10px] font-medium"
|
||||
>
|
||||
{{ formatConcurrentLimitSimple(apiKey.concurrent_limit) }}
|
||||
</Badge>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
@@ -259,6 +265,12 @@
|
||||
>
|
||||
{{ formatRateLimitSimple(apiKey.rate_limit) }}
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
class="text-[10px] px-1.5 py-0"
|
||||
>
|
||||
{{ formatConcurrentLimitSimple(apiKey.concurrent_limit) }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="flex items-center gap-0.5 flex-shrink-0">
|
||||
<Button
|
||||
@@ -355,7 +367,7 @@
|
||||
{{ editingApiKey ? '编辑 API 密钥' : '创建 API 密钥' }}
|
||||
</h3>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ editingApiKey ? '更新密钥名称和速率限制' : '创建一个新的密钥用于访问 API 服务' }}
|
||||
{{ editingApiKey ? '更新密钥名称、速率限制和并发限制' : '创建一个新的密钥用于访问 API 服务' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -400,6 +412,26 @@
|
||||
留空不限
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label
|
||||
for="key-concurrent-limit"
|
||||
class="text-sm font-semibold"
|
||||
>并发限制</Label>
|
||||
<Input
|
||||
id="key-concurrent-limit"
|
||||
:model-value="newKeyConcurrentLimit ?? ''"
|
||||
type="number"
|
||||
min="0"
|
||||
max="10000"
|
||||
placeholder="0 = 不限并发"
|
||||
class="h-11 border-border/60"
|
||||
@update:model-value="(v) => newKeyConcurrentLimit = parseNumberInput(v, { min: 0, max: 10000 })"
|
||||
/>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ editingApiKey ? '留空表示保持当前值,填 0 表示不限并发' : '留空表示不限并发,填 0 也表示不限并发' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
@@ -542,6 +574,7 @@ const showDeleteDialog = ref(false)
|
||||
|
||||
const newKeyName = ref('')
|
||||
const newKeyRateLimit = ref<number | undefined>(undefined)
|
||||
const newKeyConcurrentLimit = ref<number | undefined>(undefined)
|
||||
const newKeyValue = ref('')
|
||||
const keyToDelete = ref<ApiKey | null>(null)
|
||||
const editingApiKey = ref<ApiKey | null>(null)
|
||||
@@ -573,6 +606,7 @@ function openEditApiKeyDialog(apiKey: ApiKey) {
|
||||
editingApiKey.value = apiKey
|
||||
newKeyName.value = apiKey.name || ''
|
||||
newKeyRateLimit.value = apiKey.rate_limit ?? undefined
|
||||
newKeyConcurrentLimit.value = apiKey.concurrent_limit ?? undefined
|
||||
showCreateDialog.value = true
|
||||
}
|
||||
|
||||
@@ -580,6 +614,7 @@ function openCreateApiKeyDialog() {
|
||||
editingApiKey.value = null
|
||||
newKeyName.value = ''
|
||||
newKeyRateLimit.value = undefined
|
||||
newKeyConcurrentLimit.value = undefined
|
||||
showCreateDialog.value = true
|
||||
}
|
||||
|
||||
@@ -588,6 +623,7 @@ function closeApiKeyDialog() {
|
||||
editingApiKey.value = null
|
||||
newKeyName.value = ''
|
||||
newKeyRateLimit.value = undefined
|
||||
newKeyConcurrentLimit.value = undefined
|
||||
}
|
||||
|
||||
async function saveApiKey() {
|
||||
@@ -602,12 +638,14 @@ async function saveApiKey() {
|
||||
await meApi.updateApiKey(editingApiKey.value.id, {
|
||||
name: newKeyName.value,
|
||||
rate_limit: newKeyRateLimit.value ?? 0,
|
||||
concurrent_limit: newKeyConcurrentLimit.value,
|
||||
})
|
||||
success('API 密钥更新成功')
|
||||
} else {
|
||||
const newKey = await meApi.createApiKey({
|
||||
name: newKeyName.value,
|
||||
rate_limit: newKeyRateLimit.value ?? 0,
|
||||
concurrent_limit: newKeyConcurrentLimit.value,
|
||||
})
|
||||
newKeyValue.value = newKey.key || ''
|
||||
showKeyDialog.value = true
|
||||
@@ -711,6 +749,13 @@ function formatNumber(num: number | undefined | null): string {
|
||||
return num.toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
function formatConcurrentLimitSimple(concurrentLimit?: number | null): string {
|
||||
if (concurrentLimit == null || concurrentLimit === 0) {
|
||||
return '不限并发'
|
||||
}
|
||||
return `${concurrentLimit} 并发`
|
||||
}
|
||||
|
||||
function formatDate(dateString: string): string {
|
||||
const date = new Date(dateString)
|
||||
return date.toLocaleDateString('zh-CN', {
|
||||
|
||||
Reference in New Issue
Block a user