fix: tune sub2api codex pool concurrency

This commit is contained in:
Codex
2026-06-09 09:18:36 +00:00
parent a802a953cf
commit 4ef480bbd3
6 changed files with 86 additions and 29 deletions
+49 -2
View File
@@ -74,6 +74,7 @@ interface CodexPoolConfig {
apiKeySecretName: string;
apiKeySecretKey: string;
minOwnerBalanceUsd: number;
minOwnerConcurrency: number;
defaultAccountCapacity: number;
defaultTempUnschedulable: CodexTempUnschedulablePolicy;
profiles: CodexPoolProfileConfig[];
@@ -262,6 +263,7 @@ async function codexPoolSync(config: UniDeskConfig, options: SyncOptions): Promi
apiKeySecretName: pool.apiKeySecretName,
apiKeySecretKey: pool.apiKeySecretKey,
minOwnerBalanceUsd: pool.minOwnerBalanceUsd,
minOwnerConcurrency: pool.minOwnerConcurrency,
defaultAccountCapacity: pool.defaultAccountCapacity,
},
profiles: profiles.map((profile) => ({
@@ -567,6 +569,7 @@ function readCodexPoolConfig(): CodexPoolConfig {
apiKeySecretName: stringValue(pool.apiKeySecretName) ?? defaults.apiKeySecretName,
apiKeySecretKey: stringValue(pool.apiKeySecretKey) ?? defaults.apiKeySecretKey,
minOwnerBalanceUsd: numberValue(pool.minOwnerBalanceUsd) ?? defaults.minOwnerBalanceUsd,
minOwnerConcurrency: readAccountCapacity(pool.minOwnerConcurrency, "pool.minOwnerConcurrency"),
defaultAccountCapacity: readAccountCapacity(pool.defaultAccountCapacity, "pool.defaultAccountCapacity"),
defaultTempUnschedulable,
profiles: readProfileConfig(parsed.profiles, defaults.profiles, defaultTempUnschedulable),
@@ -579,6 +582,10 @@ function readCodexPoolConfig(): CodexPoolConfig {
throw new Error(`${codexPoolConfigPath}.pool.apiKeySecretKey must be a valid secret key name`);
}
if (config.minOwnerBalanceUsd <= 0) throw new Error(`${codexPoolConfigPath}.pool.minOwnerBalanceUsd must be > 0`);
const declaredAccountCapacity = config.profiles.reduce((total, profile) => total + (profile.capacity ?? config.defaultAccountCapacity), 0);
if (declaredAccountCapacity > 0 && config.minOwnerConcurrency < declaredAccountCapacity) {
throw new Error(`${codexPoolConfigPath}.pool.minOwnerConcurrency must be >= the sum of declared account capacities (${declaredAccountCapacity})`);
}
return config;
}
@@ -589,6 +596,8 @@ function defaultCodexPoolConfig(): CodexPoolConfig {
apiKeySecretName: defaultPoolApiKeySecretName,
apiKeySecretKey: defaultPoolApiKeySecretKey,
minOwnerBalanceUsd: defaultMinOwnerBalanceUsd,
// Only used for the no-YAML fallback path; real pool configs must declare pool.minOwnerConcurrency.
minOwnerConcurrency: 1,
defaultAccountCapacity: 5,
defaultTempUnschedulable: defaultCodexTempUnschedulablePolicy(),
profiles: [],
@@ -986,6 +995,7 @@ function poolTarget(pool = readCodexPoolConfig()): Record<string, unknown> {
groupName: pool.groupName,
apiKeyName: pool.apiKeyName,
apiKeySecret: `${namespace}/${pool.apiKeySecretName}.${pool.apiKeySecretKey}`,
minOwnerConcurrency: pool.minOwnerConcurrency,
defaultAccountCapacity: pool.defaultAccountCapacity,
valuesPrinted: false,
};
@@ -1698,6 +1708,7 @@ POOL_API_KEY_NAME = "${pool.apiKeyName}"
POOL_API_KEY_SECRET_NAME = "${pool.apiKeySecretName}"
POOL_API_KEY_SECRET_KEY = "${pool.apiKeySecretKey}"
MIN_OWNER_BALANCE_USD = ${JSON.stringify(pool.minOwnerBalanceUsd)}
MIN_OWNER_CONCURRENCY = ${JSON.stringify(pool.minOwnerConcurrency)}
POOL_DEFAULT_ACCOUNT_CAPACITY = ${JSON.stringify(pool.defaultAccountCapacity)}
EXPECTED_ACCOUNT_CAPACITIES = ${JSON.stringify(desiredAccountCapacityMap(pool))}
EXPECTED_ACCOUNT_WS_MODES = json.loads(${JSON.stringify(JSON.stringify(desiredAccountWebSocketsV2ModeMap(pool)))})
@@ -2105,6 +2116,37 @@ def ensure_pool_owner_balance(token, user_id):
"minimumBalanceUsd": MIN_OWNER_BALANCE_USD,
}
def ensure_pool_owner_concurrency(token, user_id):
user = get_admin_user(token, user_id)
try:
current = int(user.get("concurrency") or 0)
except Exception:
current = 0
if current >= MIN_OWNER_CONCURRENCY:
return {
"ok": True,
"action": "kept-existing",
"userId": user_id,
"concurrencyBefore": current,
"concurrencyAfter": current,
"minimumConcurrency": MIN_OWNER_CONCURRENCY,
}
updated = ensure_success(curl_api("PUT", f"/api/v1/admin/users/{user_id}", bearer=token, payload={
"concurrency": MIN_OWNER_CONCURRENCY,
}), "set API key owner concurrency")
try:
after = int(updated.get("concurrency") or MIN_OWNER_CONCURRENCY) if isinstance(updated, dict) else MIN_OWNER_CONCURRENCY
except Exception:
after = MIN_OWNER_CONCURRENCY
return {
"ok": after >= MIN_OWNER_CONCURRENCY,
"action": "set",
"userId": user_id,
"concurrencyBefore": current,
"concurrencyAfter": after,
"minimumConcurrency": MIN_OWNER_CONCURRENCY,
}
def validate_gateway(api_key):
resp = curl_api("GET", "/v1/models", bearer=api_key)
parsed = resp.get("json")
@@ -2369,9 +2411,10 @@ def run_sync():
api_key, secret_action, secret_apply_stdout = ensure_api_key_secret(group_id)
api_key_result = ensure_sub2api_api_key(token, api_key, group_id)
owner_balance = ensure_pool_owner_balance(token, api_key_result["userId"])
owner_concurrency = ensure_pool_owner_concurrency(token, api_key_result["userId"])
gateway = validate_gateway(api_key)
return {
"ok": gateway["ok"] is True and capacity_status["ok"] is True and ws_v2_status["ok"] is True and temp_unschedulable_status["ok"] is True,
"ok": gateway["ok"] is True and owner_concurrency["ok"] is True and capacity_status["ok"] is True and ws_v2_status["ok"] is True and temp_unschedulable_status["ok"] is True,
"mode": "sync",
"namespace": NAMESPACE,
"serviceDns": SERVICE_DNS,
@@ -2403,6 +2446,7 @@ def run_sync():
"valuesPrinted": False,
},
"ownerBalance": owner_balance,
"ownerConcurrency": owner_concurrency,
"validation": {"gatewayModels": gateway},
}
@@ -2413,14 +2457,16 @@ def run_validate():
admin_email, token = login()
key_item = next((item for item in list_user_keys(token) if item.get("key") == api_key), None)
owner_balance = None
owner_concurrency = None
if key_item is not None and key_item.get("user_id") is not None:
owner_balance = ensure_pool_owner_balance(token, key_item["user_id"])
owner_concurrency = ensure_pool_owner_concurrency(token, key_item["user_id"])
capacity_status = account_capacity_status(token)
ws_v2_status = account_ws_v2_status(token)
temp_unschedulable_status = account_temp_unschedulable_status(token)
gateway = validate_gateway(api_key)
return {
"ok": gateway["ok"] is True and capacity_status["ok"] is True and ws_v2_status["ok"] is True and temp_unschedulable_status["ok"] is True,
"ok": gateway["ok"] is True and (owner_concurrency is None or owner_concurrency["ok"] is True) and capacity_status["ok"] is True and ws_v2_status["ok"] is True and temp_unschedulable_status["ok"] is True,
"mode": "validate",
"namespace": NAMESPACE,
"serviceDns": SERVICE_DNS,
@@ -2434,6 +2480,7 @@ def run_validate():
"valuesPrinted": False,
},
"ownerBalance": owner_balance,
"ownerConcurrency": owner_concurrency,
"capacity": capacity_status,
"webSocketsV2": ws_v2_status,
"tempUnschedulable": temp_unschedulable_status,