Files
model-gateway/service/retry.go
T

54 lines
1.7 KiB
Go

package service
import (
"context"
"strings"
"time"
"gitea.redpowerfuture.com/red-future/common/oss"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
// modelCallMaxRetries 上游调用最大重试次数
const modelCallMaxRetries = 10
// retryWait 指数退避等待(第 attempt 次重试,等待 1<<attempt 秒)。
// 返回 nil 表示可继续重试;ctx 已取消返回 ctx.Err(),调用方应停止。
func retryWait(ctx context.Context, attempt int) error {
wait := time.Duration(1<<attempt) * time.Second
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(wait):
return nil
}
}
// isRetryableErrorCode 判定上游返回的错误码是否可重试:限流(429/limit_requests/limit_tokens/rate_limit_exceeded)与 5xx(500-503)。
// httpclient.ModelHttpNormalRequest 不返回 HTTP status,只能按响应体 error.code 字符串判定。
func isRetryableErrorCode(code string) bool {
switch code {
case "429", "500", "501", "502", "503", "InvalidParameter", "limit_requests", "limit_tokens", "rate_limit_exceeded":
return true
}
return false
}
// firstText 取任意值首位文本:数组取首个元素,其余原样转字符串
func firstText(v any) string {
if arr, ok := v.([]any); ok && len(arr) > 0 {
return gconv.String(arr[0])
}
return gconv.String(v)
}
// extractChunkText 从流式分片字段取值并转存 OSS,返回首位文本(数组取首个元素,去掉首尾空白)。
// 空值 / 仅空白 / 数组全空 返回空串。
func extractChunkText(ctx context.Context, v any) string {
if v == nil || g.IsEmpty(v) {
return ""
}
return strings.TrimSpace(firstText(oss.TempURLToOSS(ctx, v)))
}