初始提交:边缘AI算力机统一AI通讯层
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user