Files
freedakgmail 93a469061d
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled
CI / security-scan (push) Has been cancelled
初始提交:边缘AI算力机统一AI通讯层
2026-08-03 07:44:05 +08:00

139 lines
4.1 KiB
Go

package connector
import (
"context"
"fmt"
"time"
"github.com/edgeai/gateway/internal/config"
)
// TimeoutManager manages layered timeouts for different phases of request processing.
type TimeoutManager struct {
cfg *config.TimeoutConfig
}
// NewTimeoutManager creates a new TimeoutManager.
func NewTimeoutManager(cfg *config.TimeoutConfig) *TimeoutManager {
return &TimeoutManager{cfg: cfg}
}
// TimeoutPhase represents a phase of request processing.
type TimeoutPhase string
const (
PhaseQueue TimeoutPhase = "queue"
PhaseFirstToken TimeoutPhase = "first_token"
PhaseInference TimeoutPhase = "inference"
PhaseTotal TimeoutPhase = "total"
)
// TimeoutConfig holds resolved timeout values for a specific request.
type TimeoutConfig struct {
QueueMs int
FirstTokenMs int
InferenceMs int
TotalMs int
ConnectMs int
IdleMs int
}
// ResolveTimeouts merges request-level timeout overrides with global defaults.
func (tm *TimeoutManager) ResolveTimeouts(reqTimeouts *config.TimeoutConfig, overrides map[string]int) *TimeoutConfig {
tc := &TimeoutConfig{
QueueMs: tm.cfg.DefaultQueueMs,
FirstTokenMs: tm.cfg.DefaultFirstTokenMs,
InferenceMs: tm.cfg.DefaultInferenceMs,
TotalMs: tm.cfg.DefaultTotalMs,
ConnectMs: tm.cfg.DefaultConnectMs,
IdleMs: tm.cfg.DefaultIdleMs,
}
if overrides != nil {
if v, ok := overrides["queue_ms"]; ok && v > 0 {
tc.QueueMs = v
}
if v, ok := overrides["first_token_ms"]; ok && v > 0 {
tc.FirstTokenMs = v
}
if v, ok := overrides["inference_ms"]; ok && v > 0 {
tc.InferenceMs = v
}
if v, ok := overrides["total_ms"]; ok && v > 0 {
tc.TotalMs = v
}
}
return tc
}
// QueueContext returns a context with the queue timeout.
func (tm *TimeoutManager) QueueContext(parent context.Context, tc *TimeoutConfig) (context.Context, context.CancelFunc) {
return context.WithTimeout(parent, time.Duration(tc.QueueMs)*time.Millisecond)
}
// InferenceContext returns a context with the inference timeout.
func (tm *TimeoutManager) InferenceContext(parent context.Context, tc *TimeoutConfig) (context.Context, context.CancelFunc) {
return context.WithTimeout(parent, time.Duration(tc.InferenceMs)*time.Millisecond)
}
// TotalContext returns a context with the total request timeout.
func (tm *TimeoutManager) TotalContext(parent context.Context, tc *TimeoutConfig) (context.Context, context.CancelFunc) {
return context.WithTimeout(parent, time.Duration(tc.TotalMs)*time.Millisecond)
}
// CheckTimeout returns an error if the given phase has timed out.
func (tm *TimeoutManager) CheckTimeout(phase TimeoutPhase, elapsed time.Duration, tc *TimeoutConfig) error {
var limit time.Duration
switch phase {
case PhaseQueue:
limit = time.Duration(tc.QueueMs) * time.Millisecond
case PhaseFirstToken:
limit = time.Duration(tc.FirstTokenMs) * time.Millisecond
case PhaseInference:
limit = time.Duration(tc.InferenceMs) * time.Millisecond
case PhaseTotal:
limit = time.Duration(tc.TotalMs) * time.Millisecond
default:
return nil
}
if elapsed > limit {
return fmt.Errorf("%s timeout: elapsed %v exceeds limit %v", phase, elapsed, limit)
}
return nil
}
// CancelManager manages cancellation propagation from client to inference engine.
type CancelManager struct{}
// NewCancelManager creates a new CancelManager.
func NewCancelManager() *CancelManager {
return &CancelManager{}
}
// WatchClientDisconnect watches for client connection close and signals cancellation.
// Returns a context that is cancelled when the client disconnects.
func (cm *CancelManager) WatchClientDisconnect(r interface{ Done() <-chan struct{} }, cancel context.CancelFunc) {
go func() {
select {
case <-r.Done():
cancel()
}
}()
}
// PropagateCancel creates a derived context that is cancelled when either the parent
// context is cancelled or the cancel channel is closed.
func (cm *CancelManager) PropagateCancel(parent context.Context, cancelCh <-chan struct{}) (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(parent)
go func() {
select {
case <-cancelCh:
cancel()
case <-ctx.Done():
}
}()
return ctx, cancel
}