Files
easyai-ai-gateway/apps/api/internal/executionpool/probe.go
T
wangbo 7786692d32 feat(routing): 引入多执行池智能调度
将 Worker 发现、路由画像、容量与执行传输抽象为平台无关接口,新增 Kubernetes 和静态容量适配器,并以 shadow 模式接入生产配置。

实现网络与容量评分、路由防抖、池队列、同步 Worker 租约、一次性执行令牌,以及提交状态不明时禁止重复分配的安全语义。

新增 0105 兼容迁移、管理接口、指标、OpenAPI 和回归测试。已执行全量 Go 测试、go vet、OpenAPI、迁移安全、Compose 与 Kustomize 验证。
2026-08-05 22:25:37 +08:00

102 lines
2.3 KiB
Go

package executionpool
import (
"context"
"crypto/tls"
"net/http"
"net/http/httptrace"
"time"
)
type ProbeTarget struct {
RouteProfile RouteProfile
URL string
Method string
Timeout time.Duration
}
type ProbeResult struct {
Reachable bool
StatusCode int
DNSDuration time.Duration
TCPDuration time.Duration
TLSDuration time.Duration
FirstByte time.Duration
SampledAt time.Time
ErrorClass string
}
type NetworkProbe interface {
Probe(context.Context, ProbeTarget) ProbeResult
}
type HTTPProbe struct {
Client *http.Client
Now func() time.Time
}
func (p HTTPProbe) Probe(ctx context.Context, target ProbeTarget) ProbeResult {
result := ProbeResult{}
now := time.Now
if p.Now != nil {
now = p.Now
}
result.SampledAt = now()
method := target.Method
if method == "" {
method = http.MethodHead
}
timeout := target.Timeout
if timeout <= 0 {
timeout = 3 * time.Second
}
probeCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
var dnsStart, tcpStart, tlsStart time.Time
requestStart := now()
trace := &httptrace.ClientTrace{
DNSStart: func(httptrace.DNSStartInfo) { dnsStart = now() },
DNSDone: func(httptrace.DNSDoneInfo) {
if !dnsStart.IsZero() {
result.DNSDuration = now().Sub(dnsStart)
}
},
ConnectStart: func(_, _ string) { tcpStart = now() },
ConnectDone: func(_, _ string, _ error) {
if !tcpStart.IsZero() {
result.TCPDuration = now().Sub(tcpStart)
}
},
TLSHandshakeStart: func() { tlsStart = now() },
TLSHandshakeDone: func(tls.ConnectionState, error) {
if !tlsStart.IsZero() {
result.TLSDuration = now().Sub(tlsStart)
}
},
GotFirstResponseByte: func() { result.FirstByte = now().Sub(requestStart) },
}
request, err := http.NewRequestWithContext(httptrace.WithClientTrace(probeCtx, trace), method, target.URL, nil)
if err != nil {
result.ErrorClass = "invalid_target"
return result
}
client := p.Client
if client == nil {
client = http.DefaultClient
}
response, err := client.Do(request)
if err != nil {
if probeCtx.Err() != nil {
result.ErrorClass = "timeout"
} else {
result.ErrorClass = "network"
}
return result
}
defer response.Body.Close()
result.StatusCode = response.StatusCode
// Any HTTP response, including 401/403/404/405, proves transport reachability.
result.Reachable = true
return result
}