refactor(embedding): 删掉生产不可达的冷启动 WARN 及其 logger 缝
review round2 的 p2:`api.go` 那句「一次性冷启动放宽被花掉」的 WARN 在生产里 **不可能被人看见** —— 本包默认丢弃日志器,`WithLogger` 全树零调用者,生产走 `embedding.New(cfg)` 不带任何选项。而它的注释写着「这是唯一能审计一次性放宽的 地方」,与实际不符(本项目规则:注释不得说与实现不符的话)。 - 删该 WARN(失败并非静默:四个调用方本来就把错误原文写进各自的 WARN, 路径见 review 召回 / 整理召回 / 向量索引写入 / 检索)。 - 连带删掉 `WithLogger` 与 `log` 字段:WARN 是 `e.log` 的唯一使用者,留着它会 变成一个**空转的公开选项 + 又一次与实现不符的注释**(与上一轮删 `WithRequestTimeout` 同一条理由:不留没人用且未测的缝)。 - `callTimeout` 不再返回 `relaxed`(它只为那条 WARN 存在)。 - `NewAPI` 的注释改为把「本包不记日志、失败沿错误返回」写成**实话**。 行为零变化(生产本就是丢弃日志器),只删死代码与不实注释。
This commit is contained in:
1 parent
6c30ca540a
commit
95f517d61d
1 file changed
+10
-32
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -94,7 +93,6 @@ var ErrNoAPIURL = errors.New("embedding: api url is empty")
|
||||
type APIEmbedder struct {
|
||||
cfg config.EmbeddingConfig
|
||||
client *http.Client
|
||||
log *slog.Logger
|
||||
// warmupLeft 是**一次性**冷启动放宽的开关:为真时下一个请求用 warmupTimeout,
|
||||
// 取走即置假(CompareAndSwap ⇒ 并发下也只有一个请求能拿到)。
|
||||
// 它**不是**「未成功就一直放宽」—— 失败也照样花掉这一次,因此服务挂死时
|
||||
@@ -127,24 +125,17 @@ func WithRoundTripper(rt http.RoundTripper) APIOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger sets the logger used for embed failures. A nil logger is ignored
|
||||
// and the default discard logger is kept.
|
||||
func WithLogger(l *slog.Logger) APIOption {
|
||||
return func(e *APIEmbedder) {
|
||||
if l != nil {
|
||||
e.log = l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewAPI builds an APIEmbedder from cfg using the default HTTP client.
|
||||
// 单次超时不可由选项更换:它是 budget.go 那条推演的输入,批次上限与它同源,
|
||||
// 因此**只允许改常量**(改了之后批次上限自动跟着改,测试的编译期/常量断言立刻复核)。
|
||||
//
|
||||
// 本包**不记日志**(没有任何 logger 缝):失败一律沿错误返回,由四个调用方
|
||||
// (审查召回 / 整理召回 / 向量索引写入 / 检索)各自带 source 记账 —— 它们本来
|
||||
// 就会把错误原文写进各自的 WARN,因此这里再记一条只会是重复的第二份。
|
||||
// 单次超时也不可由选项更换:它是 budget.go 那条推演的输入,批次上限与它同源,
|
||||
// 因此**只允许改常量**(改了之后批次上限自动跟着改,测试的常量断言立刻复核)。
|
||||
func NewAPI(cfg config.EmbeddingConfig, opts ...APIOption) *APIEmbedder {
|
||||
e := &APIEmbedder{
|
||||
cfg: cfg,
|
||||
client: defaultHTTPClient(),
|
||||
log: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
}
|
||||
// 冷启动放宽是一个**一次性**许可:见 APIEmbedder.warmupLeft。
|
||||
e.warmupLeft.Store(true)
|
||||
@@ -200,21 +191,18 @@ func (e *APIEmbedder) Embed(ctx context.Context, texts []string) ([]Vector, erro
|
||||
// (成功、失败都算花掉)。因此:
|
||||
// - 本进程的第一个请求最多等 warmupTimeout(冷启动),
|
||||
// - 从第二个请求起一律 DefaultRequestTimeout —— 服务挂死时不会每次都慢。
|
||||
//
|
||||
// 返回值 relaxed 表示这一次是不是拿到了放宽,供失败时留痕。
|
||||
func (e *APIEmbedder) callTimeout() (timeout time.Duration, relaxed bool) {
|
||||
func (e *APIEmbedder) callTimeout() time.Duration {
|
||||
if e.warmupLeft.CompareAndSwap(true, false) {
|
||||
return warmupTimeout, true
|
||||
return warmupTimeout
|
||||
}
|
||||
return DefaultRequestTimeout, false
|
||||
return DefaultRequestTimeout
|
||||
}
|
||||
|
||||
// embedChunk 发**一次** /embeddings 请求。chunk 必须已经落在 batchLimitsFor 推出来
|
||||
// 的边界内(Embed 负责切),因此它的耗时上界不超过单次超时的一半。
|
||||
func (e *APIEmbedder) embedChunk(ctx context.Context, texts []string) ([]Vector, error) {
|
||||
// 先取超时(取走即花掉那次放宽),再建 ctx:放宽许可与这次请求一一对应。
|
||||
timeout, relaxed := e.callTimeout()
|
||||
callCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
callCtx, cancel := context.WithTimeout(ctx, e.callTimeout())
|
||||
defer cancel()
|
||||
|
||||
req, err := e.newEmbeddingRequest(callCtx, texts)
|
||||
@@ -224,16 +212,6 @@ func (e *APIEmbedder) embedChunk(ctx context.Context, texts []string) ([]Vector,
|
||||
|
||||
resp, err := e.client.Do(req)
|
||||
if err != nil {
|
||||
// 冷启动放宽被花掉且没成功时留一条 WARN:它是「本进程第一次请求」这个
|
||||
// 判断唯一能被事后复核的地方(此后一切失败都按常态超时快速失败)。
|
||||
// 只记两个预算与错误(错误文本里已带端点,不另记 URL,避免重复落一条
|
||||
// 可能含 userinfo 的地址)。
|
||||
if relaxed {
|
||||
e.log.Warn("embedding: one-shot cold-start allowance spent without a successful response",
|
||||
"warmup_timeout", warmupTimeout.String(),
|
||||
"steady_timeout", DefaultRequestTimeout.String(),
|
||||
"error", err)
|
||||
}
|
||||
return nil, fmt.Errorf("embedding: request: %w", err)
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
Reference in new issue
Block a user