删除请求超时

This commit is contained in:
Sakurasan
2026-09-02 13:08:32 +08:00
parent 6d951a0d61
commit 923ac79039
5 changed files with 20 additions and 26 deletions
+2 -2
View File
@@ -27,7 +27,7 @@ OT_MASTER_KEY=change-me-master-key
OT_PROXY_UPSTREAM_KEY= OT_PROXY_UPSTREAM_KEY=
OT_PROXY_UPSTREAM_BASE_URL=https://api.openai.com OT_PROXY_UPSTREAM_BASE_URL=https://api.openai.com
OT_PROXY_DEFAULT_MODEL=gpt-4o-mini OT_PROXY_DEFAULT_MODEL=gpt-4o-mini
OT_PROXY_TIMEOUT=120s OT_PROXY_TIMEOUT=300s
# 渠道健康检查 # 渠道健康检查
OT_PROXY_HEALTH_INTERVAL=60s OT_PROXY_HEALTH_INTERVAL=60s
@@ -50,4 +50,4 @@ OT_ADMIN_EMAIL=admin@localhost
OT_ADMIN_PASSWORD=admin123 OT_ADMIN_PASSWORD=admin123
# 记录原始请求日志 # 记录原始请求日志
OT_PROXY_LOG_RAW=false OT_PROXY_LOG_RAW=false
+2 -2
View File
@@ -31,7 +31,7 @@ func serve() error {
} }
defer a.Shutdown(context.Background()) defer a.Shutdown(context.Background())
gw := proxy.NewGateway(a.DB, a.Enc, a.Usage, a.Limit, cfg.RateLimit.UserRPS, cfg.Proxy.LogRaw) gw := proxy.NewGateway(a.DB, a.Enc, a.Usage, a.Limit, cfg.RateLimit.UserRPS, cfg.Proxy.LogRaw, cfg.Proxy.Timeout)
router := api.NewRouter(a, gw) router := api.NewRouter(a, gw)
srv := &http.Server{ srv := &http.Server{
@@ -59,4 +59,4 @@ func serve() error {
} }
a.Usage.Close() a.Usage.Close()
return nil return nil
} }
+9 -9
View File
@@ -59,14 +59,14 @@ type AuthConfig struct {
} }
type ProxyConfig struct { type ProxyConfig struct {
DefaultChannelName string // 首次启动自动创建的渠道名(如 openai) DefaultChannelName string // 首次启动自动创建的渠道名(如 openai)
UpstreamBaseURL string // 渠道 base_url 默认值 UpstreamBaseURL string // 渠道 base_url 默认值
UpstreamKey string // 渠道上游 key 默认值 UpstreamKey string // 渠道上游 key 默认值
DefaultModel string // 渠道模型导入时使用的模型名 DefaultModel string // 渠道模型导入时使用的模型名
Timeout time.Duration Timeout time.Duration
HealthInterval time.Duration // 渠道健康检查周期 HealthInterval time.Duration // 渠道健康检查周期
HealthFailThreshold int // 连续失败 N 次进 cooldown HealthFailThreshold int // 连续失败 N 次进 cooldown
LogRaw bool // 记录管理员原始请求体+响应到 usage_logs(调试用,默认关) LogRaw bool // 记录管理员原始请求体+响应到 usage_logs(调试用,默认关)
} }
// loadDotEnv 读取 .env 并把 KEY=VALUE 注入环境变量(AutomaticEnv 自动映射 OT_ 前缀)。 // loadDotEnv 读取 .env 并把 KEY=VALUE 注入环境变量(AutomaticEnv 自动映射 OT_ 前缀)。
@@ -127,7 +127,7 @@ func Load() (*Config, error) {
v.SetDefault("proxy.upstream_base_url", "https://api.openai.com") v.SetDefault("proxy.upstream_base_url", "https://api.openai.com")
v.SetDefault("proxy.upstream_key", "") v.SetDefault("proxy.upstream_key", "")
v.SetDefault("proxy.default_model", "gpt-4o-mini") v.SetDefault("proxy.default_model", "gpt-4o-mini")
v.SetDefault("proxy.timeout", "120s") v.SetDefault("proxy.timeout", "300s")
v.SetDefault("proxy.health_interval", "60s") v.SetDefault("proxy.health_interval", "60s")
v.SetDefault("proxy.health_fail_threshold", 2) v.SetDefault("proxy.health_fail_threshold", 2)
v.SetDefault("proxy.log_raw", false) v.SetDefault("proxy.log_raw", false)
+6 -6
View File
@@ -109,7 +109,7 @@ func contains(list []string, s string) bool {
return false return false
} }
func NewGateway(db *gorm.DB, enc *crypto.Encryptor, rec *usage.Recorder, lim *ratelimit.Limiter, userRPS int, logRaw bool) *Gateway { func NewGateway(db *gorm.DB, enc *crypto.Encryptor, rec *usage.Recorder, lim *ratelimit.Limiter, userRPS int, logRaw bool, gw_timeout time.Duration) *Gateway {
return &Gateway{ return &Gateway{
db: db, db: db,
ch: channel.NewService(db, enc), ch: channel.NewService(db, enc),
@@ -118,7 +118,7 @@ func NewGateway(db *gorm.DB, enc *crypto.Encryptor, rec *usage.Recorder, lim *ra
lim: lim, lim: lim,
userRPS: userRPS, userRPS: userRPS,
logRaw: logRaw, logRaw: logRaw,
hc: &http.Client{Timeout: 120 * time.Second}, hc: &http.Client{Timeout: gw_timeout * time.Second},
} }
} }
@@ -272,10 +272,10 @@ func upstreamPath(proto string) string {
// upstreamPlan 描述一次代理请求的上游访问方式。 // upstreamPlan 描述一次代理请求的上游访问方式。
type upstreamPlan struct { type upstreamPlan struct {
proto string // 上游协议(用于分协议 base_url) proto string // 上游协议(用于分协议 base_url)
path string // 上游路径 path string // 上游路径
body []byte // 已转换的请求体 body []byte // 已转换的请求体
lineConv func([]byte) []byte // 流式逐行转换(nil=直通) lineConv func([]byte) []byte // 流式逐行转换(nil=直通)
bodyConv func([]byte) ([]byte, error) // 非流式响应体转换(nil=直通) bodyConv func([]byte) ([]byte, error) // 非流式响应体转换(nil=直通)
} }
+1 -7
View File
@@ -3,7 +3,6 @@ package proxy
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
@@ -218,9 +217,7 @@ func (g *Gateway) proxyOne(c *gin.Context, ch *store.Channel, plan *upstreamPlan
} }
} }
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration(ch.TimeoutMS)*time.Millisecond) req, err := http.NewRequest(http.MethodPost, upstreamURL(ch, plan.proto, plan.path), bytes.NewReader(upBody))
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, upstreamURL(ch, plan.proto, plan.path), bytes.NewReader(upBody))
if err != nil { if err != nil {
return false, false, http.StatusInternalServerError, []byte("failed to build upstream request") return false, false, http.StatusInternalServerError, []byte("failed to build upstream request")
} }
@@ -242,9 +239,6 @@ func (g *Gateway) proxyOne(c *gin.Context, ch *store.Channel, plan *upstreamPlan
start := time.Now() start := time.Now()
resp, err := g.hc.Do(req) resp, err := g.hc.Do(req)
if err != nil { if err != nil {
if ctx.Err() == context.DeadlineExceeded {
return false, true, http.StatusGatewayTimeout, []byte("upstream request timed out")
}
return false, true, http.StatusBadGateway, []byte("upstream request failed: " + err.Error()) return false, true, http.StatusBadGateway, []byte("upstream request failed: " + err.Error())
} }
defer resp.Body.Close() defer resp.Body.Close()