Skip to content

Codex capacity - #6658

Open
wz2cool wants to merge 2 commits into
QuantumNous:mainfrom
wz2cool:codex-capacity
Open

Codex capacity#6658
wz2cool wants to merge 2 commits into
QuantumNous:mainfrom
wz2cool:codex-capacity

Conversation

@wz2cool

@wz2cool wz2cool commented Aug 5, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

Summary by CodeRabbit

  • New Features

    • Added production deployment configuration with API, PostgreSQL, Redis, networking, health checks, persistent storage, and configurable environment defaults.
    • Added support for configuring logging, batch updates, timezone, and node naming.
  • Bug Fixes

    • Improved handling of upstream capacity errors by presenting consistent server errors while preserving useful status and message details.
    • Streaming and non-streaming requests now handle these errors more reliably and support successful retries.
  • Configuration

    • Updated the default local API port mapping from 3000 to 3001.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR adds production Docker Compose configuration and environment defaults. It also normalizes OpenAI server_is_overloaded errors to server_error across non-streaming and streaming Responses handling, with tests for preserved response data and logging.

Changes

Production deployment configuration

Layer / File(s) Summary
Production Compose services and defaults
.env.example, docker-compose-prd.yaml, docker-compose.yml
Adds API and Redis production services, environment validation, persistence, healthchecks, networking, and changes the local API host port to 3001.

OpenAI overload error normalization

Layer / File(s) Summary
Overload error normalization contract
service/error.go, relay/channel/openai/helper.go
Adds shared error normalization and streaming event rewriting for server_is_overloaded.
Response path integration
relay/channel/openai/relay_responses.go, relay/responses_handler.go
Applies normalization to non-streaming and streaming responses and logs intercepted errors.
Normalization behavior tests
service/error_test.go, relay/channel/openai/relay_responses_billing_test.go
Tests code conversion, preserved messages and status data, streaming fields, logging, and retry behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant OpenAI
  participant ResponsesRelay
  participant ErrorNormalizer
  participant Client
  OpenAI->>ResponsesRelay: Send overloaded error
  ResponsesRelay->>ErrorNormalizer: Normalize server_is_overloaded
  ErrorNormalizer-->>ResponsesRelay: Return server_error
  ResponsesRelay-->>Client: Return normalized error
Loading

Suggested reviewers: calcium-ion

Poem

A rabbit checks the service light,
Redis guards the data tight.
Overload hops in from upstream’s gate,
It leaves as server_error, trimmed and straight.
Tests thump softly: all is right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title relates to Codex capacity handling, which is covered by the server overload error changes, but it does not describe the production Compose changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (description_diff_mismatch, ai_padded_prose). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
docker-compose-prd.yaml (2)

10-10: 🩺 Stability & Availability | 🔵 Trivial

Verify whether this stack must scale on one host.

Fixed container_name values prevent Docker Compose from creating multiple replicas and can cause collisions with another stack on the same host. If multi-instance deployment is required, remove these fields and use the service names for networking.

Also applies to: 42-42

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose-prd.yaml` at line 10, Remove the fixed container_name settings
from the affected services in the Docker Compose stack, including the new-api
service, so Compose can scale replicas and avoid naming collisions; keep service
names unchanged for networking.

9-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the production images to tested immutable references.

calciumion/new-api:latest and redis:latest can resolve to different content after a restart. This prevents reproducible rollback and can deploy untested changes. Pin each image to a tested version and digest.

Also applies to: 41-41

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose-prd.yaml` at line 9, Update the production image references in
the Docker Compose configuration, including the API image and Redis image, to
tested immutable version-and-digest references instead of the floating latest
tags. Preserve the existing service configuration while ensuring both
deployments and rollbacks resolve to the exact tested image contents.
.env.example (1)

10-10: 🗄️ Data Integrity & Integration | 🔵 Trivial

Require unique node identities for multi-instance deployments.

common/node_identity.go uses a non-empty NODE_NAME verbatim. If multiple production instances reuse this template, all audit records use new-api-node-1, so the node source is ambiguous. Require a unique value per instance or omit the fallback and use the container hostname.

  • .env.example#L10-L10: make the sample value an explicit per-instance setting.
  • docker-compose-prd.yaml#L26-L26: remove the fixed fallback or require a unique deployment value.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env.example at line 10, The NODE_NAME configuration currently permits
identical node identities across production instances. Update .env.example line
10 to use an explicit per-instance placeholder/value, and update
docker-compose-prd.yaml line 26 to remove the fixed fallback or require a unique
deployment-provided value; preserve the existing common/node_identity.go
behavior while ensuring each instance supplies a distinct identity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker-compose-prd.yaml`:
- Line 22: Update the Redis connection configuration around REDIS_CONN_STRING so
REDIS_PASSWORD is URL-encoded before being embedded in the URI, or enforce and
validate a URL-safe password alphabet; ensure passwords containing reserved URL
characters cannot alter parsing or prevent startup.

In `@service/error_test.go`:
- Around line 136-143: Extend the test around NormalizeServerOverloadError and
types.WithOpenAIError to assert that normalizedError preserves
upstreamError.StatusCode. Keep the existing error-code, message, and rewrite
assertions unchanged.

---

Nitpick comments:
In @.env.example:
- Line 10: The NODE_NAME configuration currently permits identical node
identities across production instances. Update .env.example line 10 to use an
explicit per-instance placeholder/value, and update docker-compose-prd.yaml line
26 to remove the fixed fallback or require a unique deployment-provided value;
preserve the existing common/node_identity.go behavior while ensuring each
instance supplies a distinct identity.

In `@docker-compose-prd.yaml`:
- Line 10: Remove the fixed container_name settings from the affected services
in the Docker Compose stack, including the new-api service, so Compose can scale
replicas and avoid naming collisions; keep service names unchanged for
networking.
- Line 9: Update the production image references in the Docker Compose
configuration, including the API image and Redis image, to tested immutable
version-and-digest references instead of the floating latest tags. Preserve the
existing service configuration while ensuring both deployments and rollbacks
resolve to the exact tested image contents.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d7b4fd2-9ce1-4e04-a220-971a89c5ef53

📥 Commits

Reviewing files that changed from the base of the PR and between 0ab0202 and 536d8ec.

📒 Files selected for processing (9)
  • .env.example
  • docker-compose-prd.yaml
  • docker-compose.yml
  • relay/channel/openai/helper.go
  • relay/channel/openai/relay_responses.go
  • relay/channel/openai/relay_responses_billing_test.go
  • relay/responses_handler.go
  • service/error.go
  • service/error_test.go

Comment thread docker-compose-prd.yaml
- ./logs:/app/logs
environment:
SQL_DSN: ${SQL_DSN:?SQL_DSN is required}
REDIS_CONN_STRING: redis://:${REDIS_PASSWORD:?REDIS_PASSWORD is required}@redis:6379

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repository files around docker-compose-prd.yaml:"
if [ -f docker-compose-prd.yaml ]; then
  wc -l docker-compose-prd.yaml
  cat -n docker-compose-prd.yaml | sed -n '1,80p'
else
  fd -a 'docker-compose-prd\.ya?ml$' .
fi

echo
echo "REDIS_CONN_STRING references:"
rg -n "REDIS_CONN_STRING|redis\.ParseURL|redis://" . -g '!vendor/**' -g '!node_modules/**' | head -200

echo
echo "Go redis parser probe (uses go package data at runtime only if tooling is available):"
cat > /tmp/redis_url_probe.go <<'GO'
package main
import (
	"fmt"
	neturl "net/url"
)
func main() {
 passwords := []string{
   "ok",
   "p@ss",
   "pa/ss",
   "pa:ss",
   "pa?ss",
   "pa#ss",
   "pa%ss",
 }
 for _, pw := range passwords {
   raw := fmt.Sprintf("redis://:%s@redis:6379", pw)
   u, err := neturl.Parse(raw)
   var out string
   if err == nil {
     var p string
     if u.User != nil { p, ok := u.User.Password(); ok }
     out = fmt.Sprintf("%s => host=%q user=%q pass=%q path=%q query=%q",
       raw, u.Host,
       u.User.Username(), p, u.Path, u.Query())
   } else {
     out = fmt.Sprintf("%s => error=%q", raw, err)
   }
   fmt.Println(out)
 }
}
GO
go run /tmp/redis_url_probe.go 2>/tmp/redis_probe_stderr || { echo "go run failed:"; cat /tmp/redis_probe_stderr; }
rm -f /tmp/redis_url_probe.go

Repository: QuantumNous/new-api

Length of output: 4318


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "common/redis.go relevant section:"
cat -n common/redis.go | sed -n '1,120p'

echo
echo "Go URL parser probe with explicit password output:"
cat > /tmp/redis_url_probe.go <<'GO'
package main
import (
	"fmt"
	neturl "net/url"
)
func main() {
	passwords := []string{
		"ok",
		"p@ss",
		"pa/ss",
		"pa:ss",
		"pa?ss",
		"pa#ss",
		"pa%ss",
	}
	for _, pw := range passwords {
		raw := fmt.Sprintf("redis://:%s@redis:6379", pw)
		u, err := neturl.Parse(raw)
		var out string
		if err == nil {
			var pass string
			var havePass bool
			if u.User != nil {
				pass, havePass = u.User.Password()
			}
			out = fmt.Sprintf("password=%q raw=%s => host=%q user=%q pass=%q path=%q query=%q", pw, raw, u.Host, u.User.Username(), pass, u.Path, u.Query())
		} else {
			out = fmt.Sprintf("password=%q raw=%s => error=%q", pw, raw, err)
		}
		fmt.Println(out)
	}
}
GO
go run /tmp/redis_url_probe.go 2>/tmp/redis_probe_stderr || { echo "go run failed:"; cat /tmp/redis_probe_stderr; }
rm -f /tmp/redis_url_probe.go

Repository: QuantumNous/new-api

Length of output: 4137


Do not interpolate a raw password into the Redis URI.

REDIS_PASSWORD is embedded directly into REDIS_CONN_STRING before redis.ParseURL parses it. Passwords containing @, :, /, ?, #, or raw % can change the authority or make startup fail. Pass a separately URL-encoded REDIS_CONN_STRING, or enforce a URL-safe password alphabet.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose-prd.yaml` at line 22, Update the Redis connection
configuration around REDIS_CONN_STRING so REDIS_PASSWORD is URL-encoded before
being embedded in the URI, or enforce and validate a URL-safe password alphabet;
ensure passwords containing reserved URL characters cannot alter parsing or
prevent startup.

Comment thread service/error_test.go
Comment on lines +136 to +143
openAIError := upstreamError.ToOpenAIError()
rewritten := NormalizeServerOverloadError(&openAIError)
normalizedError := types.WithOpenAIError(openAIError, upstreamError.StatusCode)

require.True(t, rewritten)
require.Equal(t, types.ErrorCode("server_error"), normalizedError.GetErrorCode())
require.Equal(t, "server_error", normalizedError.ToOpenAIError().Code)
require.Equal(t, "Selected model is at capacity.", normalizedError.Error())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the preserved HTTP status.

Line 138 passes upstreamError.StatusCode into types.WithOpenAIError, but the test does not verify the resulting status. A regression that changes the status during rewrapping will pass this test.

Proposed test assertion
 require.True(t, rewritten)
+require.Equal(t, http.StatusServiceUnavailable, normalizedError.StatusCode)
 require.Equal(t, types.ErrorCode("server_error"), normalizedError.GetErrorCode())

As per coding guidelines, “Backend tests must protect real behavior, API contracts, billing/accounting invariants, compatibility, or regression paths.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
openAIError := upstreamError.ToOpenAIError()
rewritten := NormalizeServerOverloadError(&openAIError)
normalizedError := types.WithOpenAIError(openAIError, upstreamError.StatusCode)
require.True(t, rewritten)
require.Equal(t, types.ErrorCode("server_error"), normalizedError.GetErrorCode())
require.Equal(t, "server_error", normalizedError.ToOpenAIError().Code)
require.Equal(t, "Selected model is at capacity.", normalizedError.Error())
openAIError := upstreamError.ToOpenAIError()
rewritten := NormalizeServerOverloadError(&openAIError)
normalizedError := types.WithOpenAIError(openAIError, upstreamError.StatusCode)
require.True(t, rewritten)
require.Equal(t, http.StatusServiceUnavailable, normalizedError.StatusCode)
require.Equal(t, types.ErrorCode("server_error"), normalizedError.GetErrorCode())
require.Equal(t, "server_error", normalizedError.ToOpenAIError().Code)
require.Equal(t, "Selected model is at capacity.", normalizedError.Error())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@service/error_test.go` around lines 136 - 143, Extend the test around
NormalizeServerOverloadError and types.WithOpenAIError to assert that
normalizedError preserves upstreamError.StatusCode. Keep the existing
error-code, message, and rewrite assertions unchanged.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant